Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ jobs:
run: >-
python -m unittest
tests.test_qualification_policy
tests.test_protected_policy_context
tests.test_protected_policy_check
tests.test_protected_policy_inputs
tests.test_protected_policy_issue
tests.test_regression_corpus
tests.test_regression_evidence_schema
tests.test_server_codec_counterfactual_schema
Expand All @@ -76,3 +80,24 @@ jobs:

- name: Test browser evidence boundary
run: npm run test:visual-capture

protected-parser-install:
name: Protected parser installer controls
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: '3.13'
- name: Create a disposable installer runtime
run: |
python -I -m venv "$RUNNER_TEMP/protected-parser-install"
printf '%s\n' "$RUNNER_TEMP/protected-parser-install/bin" >> "$GITHUB_PATH"
- uses: ./.github/actions/bootstrap-patched-pip # local
with:
clients: pip,python
- name: Exercise the actual isolated hash-locked installer
run: python -I tests/test_policy_dependency_install.py
77 changes: 77 additions & 0 deletions .github/workflows/protected-policy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Protected workflow policy

on:
pull_request_target:
branches: [main]
types: [opened, reopened, synchronize, ready_for_review]

permissions:
contents: read
pull-requests: read

jobs:
protected-policy:
name: Validate bounded workflow inputs
if: >-
github.repository == 'durable-workflow/.github' &&
github.ref == 'refs/heads/main' &&
github.event_name == 'pull_request_target'
runs-on: ubuntu-24.04
timeout-minutes: 10
environment: protected-policy-gate
steps:
- name: Check out the immutable protected base
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
ref: ${{ github.sha }}
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: '3.13'
- name: Create the isolated policy runtime
run: |
python -I -m venv "$RUNNER_TEMP/protected-policy-python"
printf '%s\n' "$RUNNER_TEMP/protected-policy-python/bin" >> "$GITHUB_PATH"
- name: Select verified dependency and API trust
uses: ./.github/actions/bootstrap-patched-pip # local
with:
clients: pip,python,curl,git
- name: Install only the protected hash-locked parser
run: >-
python -I -m pip --isolated install --require-hashes
--only-binary=:all: --no-deps -r qualification/requirements.lock
- name: Require protected source and the configured App identity
env:
POLICY_GATE_APP_ID: ${{ vars.POLICY_GATE_APP_ID }}
shell: bash
run: |
set -euo pipefail
test "$GITHUB_WORKFLOW_SHA" = "$GITHUB_SHA"
test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
[[ "$POLICY_GATE_APP_ID" =~ ^[1-9][0-9]{0,18}$ ]]
- name: Create the pilot-only checks token
id: app
uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0
env:
NODE_OPTIONS: --use-openssl-ca
NODE_EXTRA_CA_CERTS: ''
NODE_USE_SYSTEM_CA: '0'
NODE_TLS_REJECT_UNAUTHORIZED: '1'
with:
app-id: ${{ vars.POLICY_GATE_APP_ID }}
private-key: ${{ secrets.POLICY_GATE_APP_KEY }}
owner: durable-workflow
repositories: .github
permission-checks: write
- name: Validate data and issue the bound App check
env:
GITHUB_TOKEN: ${{ github.token }}
POLICY_CHECKS_TOKEN: ${{ steps.app.outputs.token }}
POLICY_GATE_APP_ID: ${{ vars.POLICY_GATE_APP_ID }}
POLICY_PULL_REQUEST: ${{ github.event.pull_request.number }}
POLICY_BASE_SHA: ${{ github.sha }}
POLICY_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: >-
python -I scripts/protected_policy_issue.py
--pull-request "$POLICY_PULL_REQUEST" --base-sha "$POLICY_BASE_SHA"
--expected-head "$POLICY_HEAD_SHA"
5 changes: 4 additions & 1 deletion .github/workflows/rust-docs-visual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ jobs:
cp docs/layout.css target/doc/layout.css
mkdir -p target/doc/analytics
cp docs/analytics/analytics.js target/doc/analytics/
python3 scripts/check-docs-analytics.py target/doc

- name: Check candidate analytics from the workspace root
if: steps.classify.outputs.required == 'true'
run: python3 candidate/scripts/check-docs-analytics.py candidate/target/doc

- name: Capture candidate state matrix
if: steps.classify.outputs.required == 'true'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
- name: Produce source coverage
run: |
python -m pip install --only-binary :all: coverage==7.10.7 jsonschema==4.23.0 PyYAML==6.0.2
coverage run --source=scripts,conformance/cancellation/temporal,.github/actions/bootstrap-patched-pip -m unittest tests.test_qualification_policy tests.test_regression_corpus tests.test_regression_evidence_schema tests.test_server_codec_counterfactual_schema tests.test_visual_evidence tests.test_temporal_runtime tests.test_sdk_metrics_contract tests.test_ci_trust tests.test_pip_effective_trust tests.test_cli_effective_trust tests.test_composer_trust_contract tests.test_composer_container_trust tests.test_composer_container_effective_trust
coverage run --source=scripts,conformance/cancellation/temporal,.github/actions/bootstrap-patched-pip -m unittest tests.test_qualification_policy tests.test_protected_policy_context tests.test_protected_policy_check tests.test_protected_policy_inputs tests.test_protected_policy_issue tests.test_regression_corpus tests.test_regression_evidence_schema tests.test_server_codec_counterfactual_schema tests.test_visual_evidence tests.test_temporal_runtime tests.test_sdk_metrics_contract tests.test_ci_trust tests.test_pip_effective_trust tests.test_cli_effective_trust tests.test_composer_trust_contract tests.test_composer_container_trust tests.test_composer_container_effective_trust
coverage xml -o coverage.xml
- uses: SonarSource/sonarqube-scan-action@d209202bc7d53ff1cc128f7f907dac145c9d6ae9 # v8.3.0
env:
Expand Down
50 changes: 50 additions & 0 deletions qualification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,53 @@ helpers. It is not a shell sandbox, a multi-language program analyzer or a claim
about third-party actions' internal requests. Maintainers still review dynamic
request paths and their actual configuration. Enable the target setting after
migrating all its request paths so partial rollouts remain visible.


## Protected pilot source successor

The selective successor to [the reverted pilot](https://github.com/durable-workflow/.github/pull/240)
keeps ordinary consumer preflight and Composer helper interpretation at the
accepted rollback behavior. Its shared-policy changes allow only the pinned
App-token action and the byte-exact protected workflow. The stricter input
language lives in `scripts/protected_policy_context.py`, called only by the
protected reader before the shared validator. Candidate files remain bounded
nonexecutable data; the reader and issuer run from the protected base.

The pilot accepts new run text only as newline-separated literal commands with
fixed interpreter forms. Shell expansion, operators, escapes, inline environment
assignments, evaluator options and constructed command names refuse. Literal
data flags such as `--source` remain supported. Referenced shell helpers obey the
same language, including when `bash` reads a file with a misleading extension.
Python helper text remains data; this is not whole-program behavior analysis.

Five existing control workflows contain complex shell programs. Their complete
raw file SHA-256 identities are a finite compatibility catalog in the protected
checker source, not candidate-supplied assertions or a general Bash parser. A
changed file, changed execution context, relocated copy or new complex program
cannot inherit that exception; updating the catalog requires exact source
review. The catalog does not exempt referenced shell-helper bytes, root-directory
checks or interpreter/startup environment checks. The retained cancellation
workflow is a source compatibility identity, not admission to run its fixtures.

Relative helper references require the workspace root and a reviewed shell.
YAML traversal bounds depth and expanded alias work and refuses recursive
aliases, duplicate keys and merges. These conservative protected-pilot rules do
not change ordinary caller behavior. Run the dedicated controls with:

```sh
python -m unittest tests.test_protected_policy_context tests.test_protected_policy_check tests.test_protected_policy_inputs tests.test_protected_policy_issue
```

Integration also requires the Rust analytics checker's source-root correction
and actual old/new execution controls. The visual workflow keeps the candidate
build in its existing directory, then invokes that checker from the workspace
root with an explicit build directory. The SDK owner must prove that the checker
resolves its own source assets and preserves all content assertions. A passing
central context test does not substitute for that upstream compatibility proof.

The source remains inactive. No App/key, protected variable or secret,
environment, event-policy setting, required rule or live check is provisioned.
The existing [AI contribution issue](https://github.com/durable-workflow/ai/issues/27)
waits for accepted source and a separately qualified one-repository pilot. Human
account/key authorization and the live positive/negative, expected-issuer,
concurrency and rollback controls remain separate prerequisites.
11 changes: 10 additions & 1 deletion qualification/policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
"actions/configure-pages": {
"45bfe0192ca1faeb007ade9deae92b16b8254a0d": "v6"
},
"actions/create-github-app-token": {
"64ab729a6294000f5aa4a4bc0b73d1f32bc45510": "v3.3.0"
},
"actions/deploy-pages": {
"cd2ce8fcbc39b97be8ca5fce6e763baed58fa128": "v5"
},
Expand Down Expand Up @@ -165,7 +168,13 @@
}
},
"privileged_workflow_run_consumers": {},
"pull_request_target_exceptions": []
"pull_request_target_exceptions": [
{
"target": "github-control-plane",
"path": ".github/workflows/protected-policy.yml",
"sha256": "642d204ea939ca5eba7ef51be9e4ae56a35177413caabe849315086d3d9d2d31"
}
]
},
"targets": {
"ai": {
Expand Down
5 changes: 5 additions & 0 deletions qualification/requirements.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# PyPI PyYAML 6.0.2 wheels for CPython 3.13 on glibc Linux amd64/arm64.
# Source: https://pypi.org/pypi/PyYAML/6.0.2/json
PyYAML==6.0.2 \
--hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
--hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133
12 changes: 11 additions & 1 deletion qualification/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,17 @@
"type": "object"
},
"pull_request_target_exceptions": {
"maxItems": 0,
"items": {
"additionalProperties": false,
"properties": {
"target": {"const": "github-control-plane"},
"path": {"const": ".github/workflows/protected-policy.yml"},
"sha256": {"const": "642d204ea939ca5eba7ef51be9e4ae56a35177413caabe849315086d3d9d2d31"}
},
"required": ["target", "path", "sha256"],
"type": "object"
},
"maxItems": 1,
"type": "array"
}
},
Expand Down
Loading
Loading