Repository navigation
Admit the reviewed native release workflow from its tag ref - #283
Conversation
server#957 dispatches native-release.yml from refs/tags/native-X.Y.Z so the attestation source digest equals the release commit. The central preflight refuses any privileged workflow_dispatch job outside refs/heads/main, so it needs a narrow, reviewed exception. Add workflow_trust.privileged_tag_dispatch_workflows, bound only to server/native-release.yml's four dockerhub-native jobs. A job is admitted only when it uses that environment, needs the plan job and carries the exact tag-ref predicate as a top-level conjunct. When any job relies on it, the workflow must be dispatch-only with a required tag input, and the plan job must be unconditional and unprivileged so a wrong ref fails loudly. The predicate is fixed by code, so policy data cannot loosen it, and a missing bound workflow or job fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Security review hold at exact head The repository/workflow/job/environment binding, required tag input, dispatch-only trigger, unconditional/unprivileged plan shape, missing-bound-source refusal and derived exact tag predicate are all appropriately narrow. Two fail-open gaps remain in the durable central exception:
Independent counterexample run against this exact head, in a disposable Python 3.12 container with jsonschema 4.23.0/PyYAML 6.0.2: The current Server #957 source itself does not contain either bypass; this finding is about the central exception’s future enforcement. Keep #283 unmerged and #957’s central prerequisite open until both counterexamples refuse and the accepted real workflow still passes. |
Security review of #283 found two bypasses. A publishing condition such as always() && <tag gate> replaces the implicit success() check, so it could run after a failed plan. And an unconditional plan job with its verifier removed or replaced still passed. Admitted jobs may no longer use always(), failure() or cancelled(), and no admitted job may continue on error. The binding now records the plan verifier's exact run command and env. The plan job must first check out the dispatch commit and then run that exact step, with no condition, continue-on-error, shell or working-directory change. The plan job may not continue on error, and neither the workflow nor the plan job may override run defaults. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Second bounded Security review at exact head One equivalent status bypass remains. The new pattern omits if: success() == false && github.ref == format('refs/tags/{0}', inputs.tag)An explicit status-check function suppresses GitHub’s implicit dependency Conservatively include |
An explicit success() also suppresses the implicit success dependency, so 'success() == false && <tag gate>' could run publishing after a failed plan. Refuse every status function in admitted job conditions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Security re-review clear at exact The bounded correction closes the remaining status-function bypass: the refusal now covers Independent disposable Python 3.12 verification:
The central boundary remains narrow: one workflow, four named jobs, one environment, exact checkout and verifier invocation, no status functions, continue-on-error, or run-default override. Server owns the reviewed verifier script content. Source clearance only; hosted checks and the environment-policy readbacks remain separate gates before #957 can merge or dispatch. |
|



Central-policy prerequisite (1) for durable-workflow/server#957, per Security's review hold (server#957 comment 6588879997).
Why: server#957 dispatches
native-release.ymlfromrefs/tags/native-X.Y.Z, so the build attestation's source digest equals the release commit and releases no longer race main's tip. The central preflight refuses every privilegedworkflow_dispatchjob that can run outsiderefs/heads/main, and that refusal is correct for #957 today.Change: a new
workflow_trust.privileged_tag_dispatch_workflowsbinding, used only byserver/native-release.yml. It is not a general privileged-tag allowance.aliases,build-amd64,build-arm64,publish);dockerhub-native;needstheplanjob;if:containsgithub.ref == format('refs/tags/{0}', inputs.tag)as a top-level conjunct, with no||and no negation.workflow_dispatch, with a required stringtaginput;planjob has no job condition and no environment, secrets or write permissions, so a wrong-ref dispatch fails inplaninstead of skipping green.tag_inputin code, so policy data can't loosen it. A binding whose workflow or job is missing fails, like the existingworkflow_runconsumer binding.native-release.ymlstill passes, because no job relies on the binding. This change doesn't break server CI before #957 merges.Verification: in a python:3.12 container with jsonschema 4.23.0 and PyYAML 6.0.2:
tests.test_qualification_policyhas 11 new tests and all 40 tests in the module pass. They cover:|| true, negation,!= main,startsWith,refs/headsformat);needs;0d880547and at #957's head. Both pass, and the four privileged jobs are reported. With the binding removed, #957 fails withprivileged workflow_dispatch job 'build-amd64' can run outside refs/heads/main.python -m unittesthas the same 3 failures and 47 errors on main in this container (environment-dependent tests). This branch adds 11 passing tests. Ruff finds 67 issues on both main and this branch, so none are new.The environment policy (prerequisite 3: a
native-[0-9]*tag rule ondockerhub-native, with themainrule removed after merge) is a separate admin setting. I'll apply it and read it back just before #957 merges.🤖 Generated with Claude Code