Compare commits

...

2 commits

Author SHA1 Message Date
ff1a13dabd feat: require strict signed task authorization before approval consumption
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 4s
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 09:20:57 +02:00
ebca4f5adb build: package CLI with pinned producer verifier
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 09:20:33 +02:00
14 changed files with 972 additions and 5 deletions

View file

@ -86,3 +86,5 @@ speaks in lanes and guarded plans.
not write.
- Temporary bootstrap OpenBao credentials must live outside repos, use mode
0600, be revocable, and be removed after narrower auth is working.
Packaged CLI deployment uses the reviewed [wheel + verifier bundle](docs/cli-release-bundle.md). A Python wheel alone omits the mandatory signature helper.

View file

@ -0,0 +1,82 @@
# CLI release bundle with authenticated decision verifier
The supported packaged CLI path is an explicit wheel-plus-verifier bundle. The
existing editable `uv` workflow remains for development. Installing the Python
wheel alone omits the Go helper and is incomplete for production authorization;
it continues to fail closed. This is a CLI package, not a service or the retired
`rapp-secrets-engine` deployment.
The bundle contains the Secrets wheel, the existing PyYAML runtime wheel pinned
by `uv.lock`, the verifier executable, producer license attribution, a narrow CLI
entry point and an offline installer. It never contains the test signer, signing
seed, caller credential, runtime trust/key config or backend entitlement. Optional
`clock` extras are outside this base bundle; configuring clock trust without the
separately reviewed extra continues to refuse, rather than fall back.
## Build
Use Python >=3.11, uv and the Go toolchain required by `verifier/go.mod` on the
intended Linux architecture. Supply a local compatible PyYAML wheel whose exact
filename and SHA-256 appear in `uv.lock`. The builder never discovers/downloads a
runtime dependency. The existing Hatchling build backend is now version-pinned.
```bash
python3 scripts/build_release_bundle.py \
--output /tmp/secrets-cli-reviewed-build \
--dependency-wheel /path/to/locked-compatible-pyyaml.whl
```
Builds are offline by default. In a reviewed build environment, the explicit
`--allow-build-downloads` flag permits uv to fetch the existing pinned build
backend and its build dependencies. It does not change the runtime dependency
contract. Set writable uv/Go caches as required by that build environment.
The builder first verifies the exact producer API/signature source and native
fixture hashes, builds only the verifier root package with CGO disabled, explicit
host architecture, trimmed paths, disabled VCS stamping and an empty build ID,
then builds the wheel with commit-derived `SOURCE_DATE_EPOCH`. Two builds using
the same source snapshot/toolchain/dependency wheel produce matching artifacts
and manifest. The manifest records exact source-file and artifact SHA-256s, base
commit, producer snapshot, platform and tool versions. It contains no observed
build timestamp; retain observed execution time in a separate receipt.
## Review and offline install
**Checksums prove artifact integrity, not independent package admission.** The
owner must review/admit the source, toolchain, complete bundle and manifest hash,
and control the bundle/install prefix. A manifest obtained from an untrusted
bundle does not establish that admission. Key/trust admission remains a distinct
WP14 gate. None of these steps authorizes protected OpenBao work.
Execute the reviewed installer with the independently retained manifest digest:
```bash
python3 /path/to/reviewed-bundle/install.py \
--prefix /path/to/new-owner-controlled-prefix \
--manifest-sha256 REVIEWED_MANIFEST_SHA256
/path/to/new-owner-controlled-prefix/bin/secrets-engine --help
```
The parent directory must already be owner controlled. The installer validates
platform, manifest and the entire artifact set before creating a private new
prefix, creates its venv through the existing uv convention, and installs entirely
offline from bundled wheels. It never replaces an existing prefix or installs
into standard user/system tools. A failed partial prefix is retained and marked;
retry with a new prefix after diagnosis. Removing a failed/disposable prefix is
an explicit owner operation, not an automatic cleanup of an existing path.
Use `PREFIX/bin/secrets-engine` as the admitted CLI entry point. It checks the
bundled helper's SHA-256 before CLI import or credential access and fixes
`SECRETS_ENGINE_PDP_VERIFIER` to that helper; ambient executable overrides do not
select another verifier. Missing or changed helpers refuse. There is no runtime
compilation or unsigned fallback. The internal venv scripts/programmatic API are
not a second admitted entry point and do not create package/trust admission.
Catalog/policy and independently reviewed responder trust configuration still
belong to the deploying owner. Neither is silently copied from a developer repo.
For source verification, supply `SECRETS_ENGINE_TEST_DEPENDENCY_WHEEL` and run
`pytest tests/test_release_bundle.py`. The disposable proof compares two builds,
installs offline, invokes the installed wheel's signed HTTP boundary with public
synthetic fixtures, rejects unsigned decisions, checks helper/bundle tampering,
source drift and existing-prefix refusal. No native credentials or protected
backend are involved.

View file

@ -0,0 +1,78 @@
# Strict Secrets service task-execution handoff
This is a narrow source seam for existing SECRETS-WP-0013, not a native grant or
an execute-ccr CLI. Both Access runtime-deny policy variants remain unchanged.
The proposed service subject/transport mapping and the complete native executor
still need independent owner admission. Positive source fixtures do not admit
that mapping, a policy, a caller, a production key or an OpenBao entitlement.
Platform's trusted owner process calls:
```python
from secrets_engine.task_execution_handoff import (
authorize_task_execution, consume_task_execution,
)
authorization = authorize_task_execution(cfg, entry, execution_contract=contract)
record = authorization.as_owner_handoff()
# Independently bind exact owner Plan/descriptor; reserve durable one-shot journal.
# Persist pending strict-CAS intent before calling:
consumption = consume_task_execution(cfg, authorization)
# Independently GET-confirm exact original consumption with Approval Engine's
# ExecutionConfirmationClient before journaling consume-confirmed/native work.
```
Preparation uses the existing empty fields/policy_targets/auth_targets defaults
and existing build_action_request/claim/Check validators. No caller-selected
transport, authorizer callback, policy result or raw handoff mapping is accepted.
The normal authorizer retains detached serialized request, claim and authenticated
Go-typed envelope snapshots; its existing evidence output does not expose them.
The narrow adapter reuses the validators, rather than evaluating a policy.
The adapter checks the exact descriptor in the signed context, full evaluated and
submitted request digests, approval-free digest, exact five-field native act and
native binding digest, service subject/resource/tenant correspondence and original
decision/approval/deadline bounds. Initiating/represented subject is strictly
`secrets-engine` of type `service`; the execution actor is `service:secrets-engine`.
Signed caller provenance must report `enforce`, the proposed exact Secrets
ServiceAccount principal, `flex-auth` audience and live expiry bounding the
operation deadline. This consumes the signed PDP's caller attestation; it does
not independently perform TokenReview or promote the proposed server mapping.
Human/delegation/projected-identity flags cannot substitute for this service seam.
No service_actor_binding request propagation or source-policy activation is added.
`as_owner_handoff()` returns a detached non-secret mapping with:
- execution_contract
- approval_id, request_digest, decision_id
- native_binding, approval_binding_digest, submitted_request_digest
- decision_not_before, decision_expires_at, approval_expires_at
The exact native binding is derived from the signed evaluated request using the
published Approval five-field mapping, and is compared to the served claim.
Descriptor/CCR/grant/source/catalog/target correspondence is retained end to end;
Platform still independently compiles its owner Plan and grant from owner bytes.
The mapping is evidence for that join, never a transferable bearer authorization.
Consumption accepts only the module-created opaque prepared object in that same
trusted owner process. It fixes source/config coordinates, reauthenticates using
currently admitted responder keys, and rechecks claim/decision/descriptor/caller
freshness before reading the CAS credential. Each object is reserved once before
CAS/revalidation and cannot retry after any failure or unknown outcome. Its
process-local guard complements Platform's durable cross-process journal; it is
not a replacement for that journal or process isolation.
The strict response path uses the existing CAS transport but rejects duplicate,
nonfinite or excessively deep JSON, missing/mismatched approval and decision IDs,
wrong digest/status, missing or nonboolean idempotence, historical idempotent
success, verdict fields and absent/naive/invalid consumption timestamps. The
consumption instant and post-CAS freshness must remain inside the original
bounds. No field is coerced or filled from the submitted binding. A late/uncertain
CAS may have occurred; it never licenses retry or protected native work.
The returned immutable TaskExecutionConsumption contains exact approval_id,
request_digest, decision_id, consumed_at and explicit false idempotent. It proves
only the strict CAS response observed by Secrets. Platform must independently
confirm original durable consumption using Approval's real provider client,
journal it, then recheck its exact Plan, owner sources, grant and deadlines before
any native operation. Neither a dataclass nor a caller-supplied boolean admits
execution. Existing generic CLI CAS behavior is otherwise unchanged.

View file

@ -20,7 +20,7 @@ dev = [
secrets-engine = "secrets_engine.cli:main"
[build-system]
requires = ["hatchling"]
requires = ["hatchling==1.27.0"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]

View file

@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Build wheel + pinned producer verifier; install is a separate reviewed step."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import platform
import shutil
import subprocess
import sys
import tomllib
def digest(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def run(command, **kwargs):
return subprocess.check_output(command,text=True,**kwargs).strip()
def build(root, output, dependency_wheel, uv, allow_build_downloads=False):
if platform.system() != 'Linux':
raise ValueError('this bundle supports Linux CLI only')
# No discovered keys, source rewriting, or runtime compilation.
subprocess.run([sys.executable,str(root/'scripts/check_pdp_producer_source.py')],check=True,stdout=sys.stderr)
locked=next(p for p in tomllib.loads((root/'uv.lock').read_text())['package'] if p['name']=='pyyaml')
admitted={Path(item['url']).name:item['hash'].removeprefix('sha256:') for item in locked['wheels']}
if dependency_wheel.name not in admitted or digest(dependency_wheel)!=admitted[dependency_wheel.name]:
raise ValueError('supplied PyYAML wheel does not match uv.lock')
output.mkdir(mode=0o700,parents=False,exist_ok=False)
epoch=run(['git','log','-1','--format=%ct'],cwd=root)
commit=run(['git','rev-parse','HEAD'],cwd=root)
architecture={'x86_64':'amd64','aarch64':'arm64'}.get(platform.machine())
if architecture is None:
raise ValueError('unsupported Linux architecture')
env={**os.environ,'CGO_ENABLED':'0','GOOS':'linux','GOARCH':architecture,
'GOFLAGS':'','GOWORK':'off','SOURCE_DATE_EPOCH':epoch}
(output/'bin').mkdir();(output/'wheels').mkdir()
subprocess.run(['go','build','-trimpath','-buildvcs=false','-ldflags=-buildid=',
'-o',str(output/'bin/secrets-engine-pdp-verify'),'.'],cwd=root/'verifier',env=env,check=True)
command=[uv,'--no-config','build','--wheel','--out-dir',str(output/'wheels'),str(root)]
if not allow_build_downloads:command.append('--offline')
subprocess.run(command,env=env,check=True)
wheel,=list((output/'wheels').glob('secrets_engine-*.whl'))
shutil.copyfile(dependency_wheel,output/'wheels'/dependency_wheel.name)
helper_hash=digest(output/'bin/secrets-engine-pdp-verify')
launcher=(root/'scripts/release_cli.py').read_text().replace('@HELPER_SHA256@',helper_hash)
(output/'release_cli.py').write_text(launcher)
shutil.copyfile(root/'scripts/install_release_bundle.py',output/'install.py')
shutil.copyfile(root/'verifier/LICENSE.access-engine',output/'LICENSE.access-engine')
sources=[root/'pyproject.toml',root/'uv.lock',root/'verifier/producer-source.json']
sources+=list((root/'src/secrets_engine').glob('*.py'))
sources+=list((root/'verifier/pkg/api').glob('*.go'))+list((root/'verifier/internal/sign').glob('*.go'))
sources+=[root/'verifier/main.go',root/'scripts/check_pdp_producer_source.py',
root/'scripts/build_release_bundle.py',root/'scripts/install_release_bundle.py',root/'scripts/release_cli.py']
source_hashes={str(path.relative_to(root)):digest(path) for path in sorted(sources)}
manifest={"schema":"secrets-engine.cli-bundle.v1","source_commit":commit,"source_files":source_hashes,
"source_date_epoch":int(epoch),"system":platform.system(),"machine":platform.machine(),
"python":platform.python_version(),"go":run(['go','version']),"uv":run([uv,'--version']),
"build_backend":"hatchling==1.27.0","wheel":str(wheel.relative_to(output)),
"producer":json.loads((root/'verifier/producer-source.json').read_text()),
"artifacts":{str(path.relative_to(output)):digest(path) for path in sorted(output.rglob('*')) if path.is_file()},
"admission":"checksums are integrity evidence; owner must admit the bundle/prefix independently"}
(output/'manifest.json').write_text(json.dumps(manifest,sort_keys=True,indent=2)+'\n')
return {'bundle':str(output),'manifest_sha256':digest(output/'manifest.json'),'helper_sha256':helper_hash}
def main():
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--output',type=Path,required=True)
parser.add_argument('--dependency-wheel',type=Path,required=True)
parser.add_argument('--uv',default='uv')
parser.add_argument('--allow-build-downloads',action='store_true',help='permit uv to fetch existing build-system dependencies')
args=parser.parse_args()
try:
print(json.dumps(build(Path(__file__).resolve().parents[1],args.output.resolve(),args.dependency_wheel.resolve(),
args.uv,args.allow_build_downloads),sort_keys=True))
except (OSError,ValueError,KeyError,subprocess.SubprocessError) as exc:
print('bundle build refused: '+str(exc),file=sys.stderr);return 1
return 0
if __name__=='__main__':
raise SystemExit(main())

View file

@ -0,0 +1,82 @@
#!/usr/bin/env python3
"""Install one reviewed CLI bundle offline into a new owner-controlled prefix."""
import argparse
import hashlib
import json
from pathlib import Path
import platform
import shutil
import subprocess
import sys
def digest(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def install(bundle, prefix, expected_manifest, python, uv):
manifest_path = bundle / "manifest.json"
if digest(manifest_path) != expected_manifest:
raise ValueError("bundle manifest differs from reviewed digest")
manifest = json.loads(manifest_path.read_text())
if manifest["schema"] != "secrets-engine.cli-bundle.v1":
raise ValueError("unsupported bundle")
if manifest['system'] != platform.system() or manifest['machine'] != platform.machine():
raise ValueError("bundle platform differs from installer host")
expected_files = set(manifest['artifacts']) | {'manifest.json'}
actual_files = {str(p.relative_to(bundle)) for p in bundle.rglob('*') if p.is_file()}
if actual_files != expected_files:
raise ValueError("bundle file set differs")
for name, expected in manifest['artifacts'].items():
relative = Path(name)
if relative.is_absolute() or '..' in relative.parts:
raise ValueError("invalid artifact path")
artifact = bundle / relative
if any(parent.is_symlink() for parent in (artifact,*artifact.parents)) or digest(artifact) != expected:
raise ValueError("bundle artifact missing or changed")
# Reserve once; never replace an installed prefix or follow an existing link.
prefix.mkdir(mode=0o700, parents=False, exist_ok=False)
try:
subprocess.run([uv,'--no-config','venv','--python',python,'--no-python-downloads',str(prefix/'venv')],check=True)
subprocess.run([uv,'--no-config','pip','install','--python',str(prefix/'venv/bin/python'),
'--no-index','--find-links',str(bundle/'wheels'),str(bundle/manifest['wheel'])],check=True)
(prefix/'libexec').mkdir(mode=0o700)
helper=prefix/'libexec/secrets-engine-pdp-verify'
shutil.copyfile(bundle/'bin/secrets-engine-pdp-verify',helper);helper.chmod(0o700)
(prefix/'bin').mkdir(mode=0o700)
launcher=prefix/'bin/secrets-engine'
# An absolute venv interpreter fixes the installed dependency environment.
launcher.write_text('#!'+str(prefix/'venv/bin/python')+'\n'+(bundle/'release_cli.py').read_text())
launcher.chmod(0o700)
receipt={"schema":"secrets-engine.cli-install.v1","manifest_sha256":expected_manifest,
"helper_sha256":digest(helper),"launcher_sha256":digest(launcher),"prefix":str(prefix),
"admission":"artifact integrity only; trust and keys not admitted"}
(prefix/'install-receipt.json').write_text(json.dumps(receipt,sort_keys=True,indent=2)+'\n')
return receipt
except BaseException:
# Preserve a failed prefix as evidence; never retry into a partial install.
(prefix/'INSTALL-FAILED').write_text('Incomplete installation; use a new prefix.\n')
raise
def main():
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--bundle',type=Path,default=Path(__file__).resolve().parent)
parser.add_argument('--prefix',type=Path,required=True)
parser.add_argument('--manifest-sha256',required=True)
parser.add_argument('--python',default=sys.executable)
parser.add_argument('--uv',default='uv')
args=parser.parse_args()
try:
if not args.prefix.is_absolute() or args.prefix.parent.is_symlink():
raise ValueError('prefix must be absolute with an admitted parent')
receipt=install(args.bundle.resolve(),args.prefix,args.manifest_sha256,args.python,args.uv)
print(json.dumps(receipt,sort_keys=True))
except (OSError,ValueError,KeyError,subprocess.SubprocessError) as exc:
print('bundle install refused: '+str(exc),file=sys.stderr)
return 1
return 0
if __name__=='__main__':
raise SystemExit(main())

29
scripts/release_cli.py Normal file
View file

@ -0,0 +1,29 @@
"""Narrow installed CLI entry point; rendered by build_release_bundle.py."""
import hashlib
import os
from pathlib import Path
import sys
EXPECTED_HELPER_SHA256 = "@HELPER_SHA256@"
def main():
prefix = Path(__file__).resolve().parent.parent
helper = prefix / "libexec" / "secrets-engine-pdp-verify"
try:
if helper.is_symlink() or not helper.is_file():
raise ValueError("missing helper")
if hashlib.sha256(helper.read_bytes()).hexdigest() != EXPECTED_HELPER_SHA256:
raise ValueError("changed helper")
except (OSError, ValueError):
print("secrets-engine: installed verifier missing or changed", file=sys.stderr)
return 1
# The bundle always uses its reviewed helper; ambient overrides do not select
# another executable. The owner admits runtime trust separately.
os.environ["SECRETS_ENGINE_PDP_VERIFIER"] = str(helper)
from secrets_engine.cli import main as cli_main
return cli_main()
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -23,7 +23,7 @@ from secrets_engine.execution_contract import ExecutionContract, require_executi
from secrets_engine.approval_claim import observe_pdp_approval_claim, validate_approval_claim
from secrets_engine.catalog import human_control_required
from secrets_engine.decision_check import check_decision, require_supported_pdp_address
from secrets_engine.decision_signature import load_trust
from secrets_engine.decision_signature import load_trust, strict_json
from secrets_engine.authorization import (
build_action_request,
validate_decision_envelope,
@ -70,6 +70,8 @@ class AuthorizedAction:
binding: ConsumeBinding
decision_id: str
expires_at: str
# Detached original served artifacts for the narrow task-execution handoff.
artifacts: str = field(default="", repr=False, compare=False)
@property
def id(self) -> str:
@ -380,6 +382,8 @@ def authorize_action(
),
decision_id=validated.decision_id,
expires_at=validated.expires_at,
artifacts=json.dumps({"request":expected_request,"claim":observation.claim,"envelope":envelope},
sort_keys=True,separators=(",",":"),allow_nan=False),
)
@ -391,6 +395,7 @@ def consume_approval(
binding: ConsumeBinding,
timeout_seconds: float = 3,
opener: Callable[..., Any] = credential_urlopen,
strict_response: bool = False,
) -> ConsumedApproval:
"""POST /v1/approvals/{id}/consume. Fail closed on anything but confirmed use."""
if not base_url or not base_url.startswith(("http://", "https://")):
@ -438,8 +443,8 @@ def consume_approval(
if status != 200 or len(raw) > _MAX_BODY:
raise DecisionError(_status_message(status if status != 200 else 502))
try:
payload = json.loads(raw.decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
payload = (strict_json if strict_response else json.loads)(raw.decode("utf-8"))
except (UnicodeDecodeError, ValueError, RecursionError) as exc:
raise DecisionError("approval consume returned invalid JSON") from exc
if not isinstance(payload, dict):
raise DecisionError("approval consume returned invalid payload")
@ -447,6 +452,19 @@ def consume_approval(
raise DecisionError("approval consumption was not confirmed")
if payload.get("request_digest") != binding.request_digest:
raise DecisionError("approval consume digest does not match the request")
if strict_response:
from datetime import datetime
if (payload.get("approval_id") != approval_id
or payload.get("decision_id") != binding.decision_id
or payload.get("idempotent") is not False
or any(key in payload for key in ("effect","allow","deny","decision"))):
raise DecisionError("strict task consumption correspondence refused")
try:
stamp = datetime.fromisoformat(payload["consumed_at"].replace("Z","+00:00"))
if stamp.tzinfo is None or stamp.utcoffset() is None:
raise ValueError("timezone required")
except (KeyError,TypeError,AttributeError,ValueError):
raise DecisionError("strict task consumption timestamp refused") from None
decision_id = payload.get("decision_id")
if decision_id is not None and (
not isinstance(decision_id, str) or not decision_id

View file

@ -0,0 +1,194 @@
"""Narrow service-task PEP handoff; records never grant native execution.
Platform calls preparation itself, binds its independently compiled owner Plan,
reserves/journals once, then calls strict consumption and independent Approval
GET confirmation. No inbound mapping/boolean or constructor creates authority.
Actual policy/server input mapping and runtime entitlement remain unadmitted.
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
import json
from threading import Lock
from secrets_engine.approval_auth import approval_token, credential_urlopen
from secrets_engine.approval_claim import binding_from_check_request, claim_binding_digest, validate_approval_claim
from secrets_engine.approval_consume import authorize_action, consume_approval
from secrets_engine.application_time import read_window, validity_bounds
from secrets_engine.authorization import validate_decision_envelope, request_digest, approval_binding_digest
from secrets_engine.decision_signature import authenticate_response, load_trust, strict_json
from secrets_engine.errors import DecisionError
from secrets_engine.execution_contract import ExecutionContract, require_execution_deadline
_CALLER = 'system:serviceaccount:secrets-engine:secrets-engine'
_NATIVE_FIELDS = ('action','actor','principal','purpose','target')
_COORDINATES = ('approval_url','approval_token_file','approval_client_secret_file','keycape_token_url','keycape_issuer',
'pdp_url','pdp_token_file','pdp_trust_file','pdp_verifier','clock_trust_file',
'authorization_subject_id','authorization_subject_type','authorization_policy_package','authorization_policy_version')
_ISSUED = object()
def _refuse():
raise DecisionError('strict task execution handoff correspondence refused')
def _coordinates(cfg):
return tuple(str(getattr(cfg,name,'') or '') for name in _COORDINATES)
def _stamp(value):
try:
parsed=datetime.fromisoformat(value.replace('Z','+00:00'))
if parsed.tzinfo is None or parsed.utcoffset() is None:
_refuse()
return parsed
except (AttributeError,TypeError,ValueError):
_refuse()
class TaskExecutionAuthorization:
"""Opaque process-local prepared state; not a bearer credential or allow."""
__slots__=('_action','_contract','_coordinates','_handoff','_used','_lock')
def __init__(self, issuer=None, *, action=None, contract=None, coordinates=None, handoff=None):
if issuer is not _ISSUED:
_refuse()
object.__setattr__(self,'_action',action)
object.__setattr__(self,'_contract',contract)
object.__setattr__(self,'_coordinates',coordinates)
object.__setattr__(self,'_handoff',json.dumps(handoff,sort_keys=True,separators=(',',':'),allow_nan=False))
object.__setattr__(self,'_used',False)
object.__setattr__(self,'_lock',Lock())
def __setattr__(self,name,value):
raise AttributeError('prepared task handoff is immutable')
def as_owner_handoff(self):
return strict_json(self._handoff)
@dataclass(frozen=True)
class TaskExecutionConsumption:
approval_id: str
request_digest: str
decision_id: str
consumed_at: str
idempotent: bool
def _validate(cfg, action, contract):
if type(contract) is not ExecutionContract or not action.artifacts:
_refuse()
descriptor=contract.as_dict()
artifacts=strict_json(action.artifacts)
request,claim,envelope=(artifacts[name] for name in ('request','claim','envelope'))
# Rotation/removal and installed-helper changes cannot hide behind a cached
# prepared label. Reauthenticate before each strict CAS, without networking.
authenticated=authenticate_response(json.dumps(envelope,allow_nan=False).encode(),
trust=load_trust(getattr(cfg,'pdp_trust_file',None)),
verifier=getattr(cfg,'pdp_verifier',None))
if authenticated != envelope:
_refuse()
window=read_window(cfg)
lower,upper=validity_bounds(window=window)
validated=validate_decision_envelope(envelope,request,
accepted_policy_packages={str(cfg.authorization_policy_package)},
accepted_policy_versions={str(cfg.authorization_policy_version)},
expected_approval_binding_digest=claim['binding']['pdp_digest'],time_window=window)
validate_approval_claim(claim,approval_id=action.binding.approval_id,
expected_pdp_digest=envelope['binding']['approval_binding_digest'],
require_human_control=True,time_window=window)
require_execution_deadline(request,time_window=window,
bounds=(claim['validity']['expires_at'],envelope['lifetime']['expires_at']))
binding=envelope['binding']
if (envelope['lifetime'].get('kind')!='ttl'
or _stamp(envelope['lifetime'].get('not_before'))>lower):
_refuse()
if (request['action']!='execute-ccr' or binding.get('action')!='execute-ccr'
or request['tenant']!='tenant:platform' or binding.get('tenant')!='tenant:platform'
or binding.get('context')!=request['context']
or request['context'].get('execution_contract')!=descriptor
or binding.get('request_digest')!=request_digest(binding)
or binding.get('approval_binding_digest')!=approval_binding_digest(binding)
or action.binding.request_digest!=validated.request_digest
or action.binding.decision_id!=validated.decision_id):
_refuse()
subject=binding['subject']; resource=binding['resource']
if (request['subject']!={'id':'secrets-engine','type':'service'}
or subject.get('id')!='secrets-engine' or subject.get('type')!='service'
or subject.get('tenant') not in (None,'tenant:platform')
or 'principal' in subject.get('attributes',{})
or envelope['subject']!=subject or envelope['resource']!=resource
or descriptor['execution_actor']!='service:secrets-engine'
or any(resource.get(key)!=request['resource'].get(key) for key in ('id','type','system'))
or resource.get('tenant') not in (None,'tenant:platform')
or any(resource.get('attributes',{}).get(key)!=value for key,value in request['resource']['attributes'].items())
or any(key in binding['context'] for key in ('task_execution_projection','initiator','represented_principal','delegation','verified','owner_admission'))):
_refuse()
caller=envelope['provenance'].get('caller')
if (not isinstance(caller,dict) or caller.get('mode')!='enforce'
or caller.get('principal')!=_CALLER or caller.get('audience')!='flex-auth'
or _stamp(caller.get('not_after')) < _stamp(descriptor['operation_deadline'])
or upper >= _stamp(caller.get('not_after'))):
_refuse()
native=binding_from_check_request(binding)
supplied=claim['binding']
# Recompute the served native act too: Python equality alone conflates
# boolean/integer enrichment and cannot establish canonical correspondence.
if (any(supplied.get(key)!=native[key] for key in _NATIVE_FIELDS)
or supplied.get('digest')!=claim_binding_digest(**native)
or supplied.get('digest')!=claim_binding_digest(**{key:supplied.get(key) for key in _NATIVE_FIELDS})):
_refuse()
return {'execution_contract':descriptor,'approval_id':action.binding.approval_id,
'request_digest':validated.request_digest,'decision_id':validated.decision_id,
'native_binding':native,'approval_binding_digest':binding['approval_binding_digest'],
'submitted_request_digest':validated.submitted_request_digest,
'decision_not_before':envelope['lifetime'].get('not_before') or '',
'decision_expires_at':envelope['lifetime']['expires_at'],
'approval_expires_at':claim['validity']['expires_at']}
def authorize_task_execution(cfg, entry, *, execution_contract):
if type(execution_contract) is not ExecutionContract:
_refuse()
# No injected transports or policy callbacks: use the actual existing PIP/PDP
# clients and mandatory signature validators in the owner process.
action=authorize_action(cfg,entry,'execute-ccr',execution_contract=execution_contract)
if action is None:
_refuse()
try:
handoff=_validate(cfg,action,execution_contract)
return TaskExecutionAuthorization(_ISSUED,action=action,contract=ExecutionContract.parse(execution_contract.as_dict()),
coordinates=_coordinates(cfg),handoff=handoff)
except (ValueError,KeyError,TypeError,RecursionError) as exc:
raise DecisionError('strict task execution handoff malformed') from exc
def consume_task_execution(cfg, authorization):
if type(authorization) is not TaskExecutionAuthorization:
_refuse()
with authorization._lock:
if authorization._used or _coordinates(cfg)!=authorization._coordinates:
_refuse()
# Reserve once before all work; failures/unknown outcomes never retry this
# prepared object. Platform's durable journal is the cross-process guard.
object.__setattr__(authorization,'_used',True)
try:
handoff=_validate(cfg,authorization._action,authorization._contract)
if handoff!=authorization.as_owner_handoff():
_refuse()
result=consume_approval(base_url=str(cfg.approval_url),
token_provider=lambda:approval_token(cfg,scope='approval:consume'),
binding=authorization._action.binding,opener=credential_urlopen,strict_response=True)
stamp=_stamp(result.consumed_at)
window=read_window(cfg);_,upper=validity_bounds(window=window)
if (stamp>upper or (handoff['decision_not_before'] and stamp<_stamp(handoff['decision_not_before']))
or any(stamp>=_stamp(value) for value in (handoff['decision_expires_at'],handoff['approval_expires_at'],
handoff['execution_contract']['operation_deadline']))):
_refuse()
# Late CAS completion is historical evidence only; refuse native dispatch.
_validate(cfg,authorization._action,authorization._contract)
return TaskExecutionConsumption(result.approval_id,result.request_digest,result.decision_id,result.consumed_at,result.idempotent)
except (ValueError,KeyError,TypeError,RecursionError) as exc:
raise DecisionError('strict task execution consumption malformed') from exc

View file

@ -0,0 +1,137 @@
"""Actual offline installation proof; only supplied locked public dependency wheel.
Set SECRETS_ENGINE_TEST_DEPENDENCY_WHEEL to a local PyYAML wheel from uv.lock.
No production install, trust admission, backend or credential is used.
"""
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import pytest
from tests.test_decision_signature import FIXTURE, PUBLIC
from tests.test_decision_transport import server
ROOT = Path(__file__).resolve().parents[1]
def run(command, **kwargs):
return subprocess.run(command, text=True, capture_output=True, timeout=120, **kwargs)
@pytest.fixture(scope='module')
def bundles(tmp_path_factory):
dependency=os.environ.get('SECRETS_ENGINE_TEST_DEPENDENCY_WHEEL')
if not dependency:
pytest.skip('provide the locked public PyYAML wheel for actual bundle build/install tests')
directory=tmp_path_factory.mktemp('cli-bundles')
result=[]
for name in ['one','two']:
bundle=directory/name
built=run([sys.executable,str(ROOT/'scripts/build_release_bundle.py'),'--output',str(bundle),
'--dependency-wheel',dependency])
assert built.returncode==0,built.stderr
result.append(bundle)
return result
def manifest_hash(bundle):
return hashlib.sha256((bundle/'manifest.json').read_bytes()).hexdigest()
def install(bundle,prefix):
return run([sys.executable,str(bundle/'install.py'),'--bundle',str(bundle),'--prefix',str(prefix),
'--manifest-sha256',manifest_hash(bundle)])
@pytest.fixture
def installed(bundles,tmp_path):
prefix=tmp_path/'installed'
result=install(bundles[0],prefix)
assert result.returncode==0,result.stderr
return prefix
def test_two_builds_match_and_contain_no_signer(bundles):
one,two=bundles
names={str(path.relative_to(one)) for path in one.rglob('*') if path.is_file()}
assert names=={str(path.relative_to(two)) for path in two.rglob('*') if path.is_file()}
for name in names:
assert (one/name).read_bytes()==(two/name).read_bytes(),name
assert not any('signer' in name or 'testsupport' in name for name in names)
assert (one/'bin/secrets-engine-pdp-verify').is_file()
assert len(list((one/'wheels').glob('secrets_engine-*.whl')))==1
def test_clean_install_uses_installed_wheel_and_signed_boundary(installed,tmp_path):
env={**os.environ,'SECRETS_ENGINE_PDP_VERIFIER':'/must-not-use-ambient-override'}
help_result=run([str(installed/'bin/secrets-engine'),'--help'],env=env,cwd='/tmp')
assert help_result.returncode==0,help_result.stderr
envelope=json.loads(FIXTURE.read_bytes())
trust={name:envelope['provenance'][name] for name in ('evaluator','mode','policy_package','policy_version','policy_package_digest')}
trust.update(schema='secrets-engine.pdp-trust.v1',keys={'testdata-ed25519':PUBLIC})
trust_file=tmp_path/'synthetic-trust.json';trust_file.write_text(json.dumps(trust))
token=tmp_path/'synthetic.token';token.write_text('synthetic-pdp-credential');token.chmod(0o600)
script='''import pathlib,sys
import secrets_engine.decision_check as installed
from secrets_engine.errors import DecisionError
assert str(pathlib.Path(installed.__file__).resolve()).startswith(sys.argv[1]+'/venv/')
try:
result=installed.check_decision(base_url=sys.argv[2],token_file=pathlib.Path(sys.argv[3]),request={},trust_file=pathlib.Path(sys.argv[4]),verifier=pathlib.Path(sys.argv[1]+'/libexec/secrets-engine-pdp-verify'))
except DecisionError:
if sys.argv[5]=='refuse':sys.exit(0)
raise
assert sys.argv[5]=='accept' and result['effect']=='allow'
'''
clean_env={key:value for key,value in os.environ.items() if key not in ('PYTHONPATH','PYTHONHOME')}
for body,expect in [(FIXTURE.read_bytes(),'accept'),(b'{"effect":"allow"}','refuse')]:
with server(body=body) as (origin,seen):
result=run([str(installed/'venv/bin/python'),'-c',script,str(installed),origin,str(token),str(trust_file),expect],env=clean_env,cwd='/tmp')
assert result.returncode==0,result.stderr
assert seen==[True]
@pytest.mark.parametrize('change',['missing','tampered'])
def test_installed_cli_refuses_missing_or_tampered_helper(installed,change):
helper=installed/'libexec/secrets-engine-pdp-verify'
if change=='missing':helper.rename(helper.with_suffix('.held'))
else:helper.write_bytes(helper.read_bytes()+b'tampered')
result=run([str(installed/'bin/secrets-engine'),'--help'],cwd='/tmp')
assert result.returncode==1
assert 'verifier missing or changed' in result.stderr
assert not result.stdout
def test_installer_refuses_changed_artifact_and_existing_prefix(bundles,tmp_path):
altered=tmp_path/'altered';shutil.copytree(bundles[0],altered)
helper=altered/'bin/secrets-engine-pdp-verify';helper.write_bytes(helper.read_bytes()+b'tampered')
prefix=tmp_path/'must-not-create'
result=install(altered,prefix)
assert result.returncode==1 and not prefix.exists()
existing=tmp_path/'existing';existing.mkdir();marker=existing/'keep';marker.write_text('unchanged')
result=install(bundles[0],existing)
assert result.returncode==1 and marker.read_text()=='unchanged'
assert sorted(path.name for path in existing.iterdir())==['keep']
def test_installer_requires_exact_reviewed_manifest(bundles,tmp_path):
prefix=tmp_path/'must-not-create'
result=run([sys.executable,str(bundles[0]/'install.py'),'--prefix',str(prefix),'--manifest-sha256','0'*64])
assert result.returncode==1 and not prefix.exists()
def test_changed_producer_source_stops_before_build(tmp_path):
root=tmp_path/'source';(root/'scripts').mkdir(parents=True)
for name in ['build_release_bundle.py','check_pdp_producer_source.py']:
shutil.copyfile(ROOT/'scripts'/name,root/'scripts'/name)
shutil.copytree(ROOT/'verifier',root/'verifier')
shutil.copytree(ROOT/'tests/fixtures/pdp-signature',root/'tests/fixtures/pdp-signature')
source=root/'verifier/internal/sign/sign.go';source.write_bytes(source.read_bytes()+b'// drift\n')
output=tmp_path/'must-not-build'
result=run([sys.executable,str(root/'scripts/build_release_bundle.py'),'--output',str(output),
'--dependency-wheel',str(tmp_path/'not-reached.whl')])
assert result.returncode==1 and not output.exists()

View file

@ -0,0 +1,231 @@
"""Real local HTTP/producer signatures, synthetic approval/caller only.
These source fixtures never enable Access's runtime-deny policy or admit a real
caller, key, owner grant or native backend. Whole-provider integration is separate.
"""
import copy
from datetime import datetime, timedelta, timezone
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import json
from pathlib import Path
from threading import Thread
import pytest
from secrets_engine.approval_claim import binding_from_check_request, claim_binding_digest
from secrets_engine.approval_consume import _expected_request
from secrets_engine.authorization import request_digest, approval_binding_digest
from secrets_engine.errors import DecisionError
from secrets_engine.execution_contract import ExecutionContract
from secrets_engine.task_execution_handoff import (authorize_task_execution,consume_task_execution,
TaskExecutionAuthorization)
from tests.authorization_stub import AuthorizationStub
from tests.signature_support import signature_tools, admit_tools, sign_envelope
from tests.test_consume_binding_join import _Cfg,_token,APPROVAL_ID
from tests.test_execution_context import entry,descriptor
def stamp(moment):
return moment.isoformat()
@pytest.fixture
def lane(tmp_path,signature_tools):
e=entry();contract=ExecutionContract.parse(descriptor(e))
cfg=_Cfg(_token(tmp_path),authorization_subject_id='secrets-engine',authorization_subject_type='service')
admit_tools(cfg,tmp_path,signature_tools)
original=_expected_request(cfg,e,'execute-ccr',execution_contract=contract)
stub=AuthorizationStub(approval_id=APPROVAL_ID,package=cfg.authorization_policy_package,version=cfg.authorization_policy_version)
stub.bind_request(original)
state={'calls':[],'claim_change':None,'decision_change':None,'response_change':None,'raw_response':None}
claim=stub.claim();native=binding_from_check_request(original)
claim['binding'].update(native,digest=claim_binding_digest(**native),human_control=True)
state['claim']=claim
class Handler(BaseHTTPRequestHandler):
def log_message(self,*_args):pass
def reply(self,payload):
data=json.dumps(payload).encode() if isinstance(payload,dict) else payload
self.send_response(200);self.send_header('Content-Type','application/json');self.send_header('Content-Length',str(len(data)));self.end_headers();self.wfile.write(data)
def do_GET(self):
state['calls'].append('claim')
value=copy.deepcopy(state['claim'])
if state['claim_change']:state['claim_change'](value)
self.reply(value)
def do_POST(self):
submitted=json.loads(self.rfile.read(int(self.headers['Content-Length'])))
if self.path=='/v1/check':
state['calls'].append('check')
envelope=stub.decision(submitted)
envelope['provenance']['caller']={'mode':'enforce','principal':'system:serviceaccount:secrets-engine:secrets-engine',
'audience':'flex-auth','not_after':stamp(datetime.now(timezone.utc)+timedelta(minutes=20))}
if state['decision_change']:state['decision_change'](envelope)
self.reply(sign_envelope(envelope,signature_tools))
else:
state['calls'].append('consume')
payload={'approval_id':APPROVAL_ID,'status':'consumed','request_digest':submitted['request_digest'],
'decision_id':submitted['decision_id'],'consumed_at':stamp(datetime.now(timezone.utc)),'idempotent':False}
if state['response_change']:state['response_change'](payload)
self.reply(state['raw_response'] if state['raw_response'] is not None else payload)
httpd=ThreadingHTTPServer(('127.0.0.1',0),Handler)
thread=Thread(target=httpd.serve_forever,kwargs={'poll_interval':0.01},daemon=True);thread.start()
cfg.approval_url=cfg.pdp_url=f'http://127.0.0.1:{httpd.server_port}'
try:yield cfg,e,contract,state
finally:httpd.shutdown();httpd.server_close();thread.join(2)
def prepared(lane):
cfg,e,contract,state=lane
return authorize_task_execution(cfg,e,execution_contract=contract)
def test_exact_preparation_then_one_strict_cas(lane):
cfg,e,contract,state=lane
result=prepared(lane)
assert state['calls']==['claim','check']
handoff=result.as_owner_handoff()
assert set(handoff)=={'execution_contract','approval_id','request_digest','decision_id','native_binding','approval_binding_digest',
'submitted_request_digest','decision_not_before','decision_expires_at','approval_expires_at'}
assert handoff['execution_contract']==contract.as_dict()
assert handoff['native_binding']==binding_from_check_request(_expected_request(cfg,e,'execute-ccr',execution_contract=contract))
changed=result.as_owner_handoff();changed['execution_contract']['ccr_id']='changed'
assert result.as_owner_handoff()==handoff
with pytest.raises(AttributeError):result._handoff='changed'
receipt=consume_task_execution(cfg,result)
assert receipt.approval_id==handoff['approval_id'] and receipt.request_digest==handoff['request_digest']
assert receipt.decision_id==handoff['decision_id'] and receipt.idempotent is False
assert state['calls']==['claim','check','consume']
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
assert state['calls'].count('consume')==1
@pytest.mark.parametrize('field',['action','actor','principal','purpose','target','digest'])
def test_changed_native_claim_refuses_before_cas(lane,field):
cfg,e,contract,state=lane
def change(claim):claim['binding'][field]={'id':'other'} if field=='target' else 'other'
state['claim_change']=change
with pytest.raises(DecisionError):prepared(lane)
assert 'consume' not in state['calls']
@pytest.mark.parametrize('field',['mode','principal','audience','not_after'])
def test_signed_wrong_caller_refuses_before_cas(lane,field):
cfg,e,contract,state=lane
state['decision_change']=lambda envelope:envelope['provenance']['caller'].__setitem__(field,'wrong')
with pytest.raises(DecisionError):prepared(lane)
assert 'consume' not in state['calls']
@pytest.mark.parametrize('field',['execution_actor','execution_grant_ccr_id','grant_immutable_sha256','ccr_id','backend_origin'])
def test_signed_changed_descriptor_refuses_before_cas(lane,field):
cfg,e,contract,state=lane
def change(envelope):envelope['binding']['context']['execution_contract'][field]='wrong'
state['decision_change']=change
with pytest.raises(DecisionError):prepared(lane)
assert 'consume' not in state['calls']
@pytest.mark.parametrize('field',['subject','resource','request_digest','submitted_request_digest','approval_binding_digest'])
def test_signed_changed_request_correspondence_refuses_before_cas(lane,field):
cfg,e,contract,state=lane
def change(envelope):
envelope['binding'][field]={'id':'other'} if field in ('subject','resource') else 'sha256:'+'0'*64
state['decision_change']=change
with pytest.raises(DecisionError):prepared(lane)
assert 'consume' not in state['calls']
@pytest.mark.parametrize('field',['approval_id','decision_id','request_digest','status','consumed_at','idempotent'])
def test_cas_correspondence_never_coerces_or_falls_back(lane,field):
cfg,e,contract,state=lane;result=prepared(lane)
state['response_change']=lambda payload:payload.__setitem__(field,'wrong')
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
assert state['calls'].count('consume')==1
@pytest.mark.parametrize('value',[True,1,0,'false',None])
def test_nonfresh_or_nonboolean_idempotence_refuses(lane,value):
cfg,e,contract,state=lane;result=prepared(lane)
state['response_change']=lambda payload:payload.__setitem__('idempotent',value)
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
@pytest.mark.parametrize('body',[b'{"status":"consumed","status":"consumed"}',b'{"status":NaN}',b'['*2000+b'0'+b']'*2000])
def test_duplicate_nonfinite_or_deep_consume_body_refuses(lane,body):
cfg,e,contract,state=lane;result=prepared(lane)
state['raw_response']=body
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
@pytest.mark.parametrize('field',['pdp_url','approval_url','authorization_subject_id','authorization_policy_version','pdp_verifier'])
def test_changed_owner_coordinates_refuse_before_cas(lane,field):
cfg,e,contract,state=lane;result=prepared(lane);setattr(cfg,field,'changed')
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
assert 'consume' not in state['calls']
def test_removed_signer_refuses_before_cas(lane):
cfg,e,contract,state=lane;result=prepared(lane)
trust=json.loads(cfg.pdp_trust_file.read_text());trust['keys']={'other':next(iter(trust['keys'].values()))}
cfg.pdp_trust_file.write_text(json.dumps(trust))
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
assert 'consume' not in state['calls']
def test_mapping_boolean_and_public_constructor_are_not_authority(lane):
cfg,e,contract,state=lane
for value in [True,{},object()]:
with pytest.raises(DecisionError):consume_task_execution(cfg,value)
with pytest.raises(DecisionError):TaskExecutionAuthorization()
assert not state['calls']
@pytest.mark.parametrize('field',['approval_id','decision_id','consumed_at','idempotent'])
def test_absent_cas_fields_cannot_fall_back(lane,field):
cfg,e,contract,state=lane;result=prepared(lane)
state['response_change']=lambda payload:payload.pop(field)
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
assert state['calls'].count('consume')==1
def test_expired_preparation_refuses_before_cas(lane,monkeypatch):
from types import SimpleNamespace
import secrets_engine.task_execution_handoff as module
cfg,e,contract,state=lane;result=prepared(lane)
later=int((datetime.now(timezone.utc)+timedelta(minutes=2)).timestamp()*1_000_000_000)
monkeypatch.setattr(module,'read_window',lambda cfg:SimpleNamespace(lower_ns=later,upper_ns=later))
with pytest.raises(DecisionError):consume_task_execution(cfg,result)
assert 'consume' not in state['calls']
@pytest.mark.parametrize('change',['deny','expired','missing-caller','missing-start'])
def test_signed_decision_missing_authority_refuses_before_cas(lane,change):
cfg,e,contract,state=lane
def alter(envelope):
if change=='deny':envelope['effect']='deny'
elif change=='expired':envelope['lifetime']['expires_at']=stamp(datetime.now(timezone.utc)-timedelta(seconds=1))
elif change=='missing-start':envelope['lifetime'].pop('not_before')
else:envelope['provenance'].pop('caller')
state['decision_change']=alter
with pytest.raises(DecisionError):prepared(lane)
assert 'consume' not in state['calls']
def test_native_binding_equality_does_not_coerce_boolean_enrichment(lane):
cfg,e,contract,state=lane
evaluated=_expected_request(cfg,e,'execute-ccr',execution_contract=contract)
evaluated['resource']['attributes']['synthetic_rank']=1
native=binding_from_check_request(evaluated)
state['claim']['binding'].update(copy.deepcopy(native),digest=claim_binding_digest(**native),
pdp_digest=approval_binding_digest(evaluated))
# Python dict equality treats True == 1. This malformed provider fact must
# refuse even when its reported native digest names the integer counterpart.
state['claim']['binding']['target']['attributes']['synthetic_rank']=True
def enrich(envelope):
envelope['resource']['attributes']['synthetic_rank']=1
envelope['binding']['request_digest']=request_digest(envelope['binding'])
envelope['binding']['approval_binding_digest']=approval_binding_digest(envelope['binding'])
state['decision_change']=enrich
with pytest.raises(DecisionError):prepared(lane)
assert 'consume' not in state['calls']

View file

@ -28,3 +28,8 @@ The Check API defaults to mandatory authentication. Its deliberately named
`allow_unsigned_test_fixture` argument is used only by synthetic transport tests;
production `authorize_action` never passes it. The helper runs with an empty
environment, so ambient backend and identity credentials cannot reach it.
For the complete reproducible CLI build and offline fresh-prefix installation,
use [the release bundle contract](../docs/cli-release-bundle.md). This replaces
manual helper copying for packaged deployments; package and key admission remain
separate owner decisions.

View file

@ -9,7 +9,7 @@ flavor: planning
owner: codex
topic_slug: netkingdom
created: "2026-10-11"
updated: "2026-10-11"
updated: "2026-10-16"
depends_on: []
state_hub_workstream_id: "5e38aecc-85ca-5f55-94c6-9fbb08604819"
---
@ -110,3 +110,17 @@ This is source preparation awaiting independent technical review/publication,
not a formal owner assent, policy deployment or native execution milestone. T01
remains progress; T03 and SECRETS-WP-0008-T06 remain open. Detailed limitations
and retained failed test observations are in the source preparation receipt.
2026-10-16 bounded source handoff preparation: `task_execution_handoff.py` uses
the actual serving approval/mandatory signed Check path and retained detached
artifacts to check exact descriptor/request/native approval/caller/lifetime joins,
then performs one strict exact-response CAS only after Platform journal admission.
It accepts no inbound boolean/mapping/authorizer callback and grants no native
execution. Platform independently confirms durable consumption with the actual
Approval provider client before native dispatch. Focused local HTTP/native Go
producer-signature source checks cover altered joins/caller/grant, missing fields,
coercion/idempotence, expiry, signer removal and replay refusal. No service binding
propagation, policy gate flip, identity mapping admission or production trust/key
change was made. Independent source integration/review and actual whole-provider
proof remain required. T01/T03 and WP8-T06 retain their open native obligations.

View file

@ -77,6 +77,15 @@ key admission remains part of its scope; T03 stays wait. WP13 execution and
identity-only CCR38 are unchanged. Custodian source/verification handoff:
`docs/changes/netkingdom-target-2026-10-16/decision-auth/` in the Custodian repo.
2026-10-16 packaging preparation: `scripts/build_release_bundle.py` and its
separate offline installer deliver the existing wheel plus the reviewed producer
verifier together into a new owner-controlled prefix. Source/hash drift checks,
artifact/toolchain receipts and a narrow fixed-helper launcher remove the silent
wheel-only deployment gap. Disposable build/install tests prove deterministic
artifacts, signed HTTP consumption and missing/tampered artifact refusal; they do
not admit packages, keys or a production prefix. T02 remains progress and T03
wait; no native installation, trust change or protected entitlement is claimed.
## Verify the admitted native consumer and rotation path
```task