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
6 changes: 4 additions & 2 deletions qualification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,10 @@ part of the Server hook's combined qualification.

### Composer through a reviewed PHP launcher

The catalog currently admits no PHP CI launcher in `runtime_setups`. The earlier
Sample App, CLI and Waterline records were withdrawn after the
The catalog admits only Waterline's corrected PHP 8.2 build launcher in
`runtime_setups`, with read-only controls, twelve exact source bindings and
canonical Git modes. Its final hosted caller qualification remains separate.
The earlier writable Sample App, CLI and Waterline records were withdrawn after the
[writable control-path finding](https://github.com/durable-workflow/.github/issues/297#issuecomment-6854260334).
Their repository/state mounts allowed container code to replace a host launcher
or wrapper before a later nominal verifier invocation. Historical source or TLS
Expand Down
69 changes: 68 additions & 1 deletion qualification/composer-container-trust.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,72 @@
]
}
},
"runtime_setups": {}
"runtime_setups": {
"waterline-php82-build": {
"target": "waterline",
"workflows": {
"php.yml": [
"build"
]
},
"commands": [
"bash \"$GITHUB_WORKSPACE/scripts/ci/setup-php-container.sh\" \"8.2\""
],
"environment": [
"WATERLINE_PHP_CI_IMAGE",
"WATERLINE_PHP_CI_ROOT",
"WATERLINE_PHP_CI_STATE"
],
"files": {
"docker/php-ci/Dockerfile": {
"sha256": "81d23fbbee7e4ee97ca14df9d17982aa664335b94499c5019662259fe0387eaa",
"mode": 420
},
"docker/php-ci/Dockerfile.dockerignore": {
"sha256": "a26d7f1f5ae2cac900e5e32bfaa0f08bd7a8435847095990c9bfe09d0edbf264",
"mode": 420
},
"docker/php-ci/verify-php-trust.php": {
"sha256": "529c282e7422202bf25565431a6391de388f86dfe5bfd6c75cf21daa56ffa75e",
"mode": 420
},
"docker/brotli/install-vendor.sh": {
"sha256": "d7eb8b2a3e0af1c3072a56bcb81632b22f061f211d8fe5e57ee901c8bf94c92f",
"mode": 420
},
"docker/brotli/verify-runtime.php": {
"sha256": "580cc465e349f3872eca592355294e7320fe7f1a4560ff5d4c83d5900921c00e",
"mode": 420
},
"docker/brotli/verify-system-brotli.c": {
"sha256": "3353927d206aaf5e63157e46be715c6cbee46bac777e29f8f9e25c4c1f656667",
"mode": 420
},
"docker/brotli/version": {
"sha256": "e064953e075ddb99fb7b48ad29e215f2dfa075812c127eb1d6ab680e9920fba2",
"mode": 420
},
"scripts/ci/php-container-images.json": {
"sha256": "3314ecfd6c32641af1d5475f8e57f4421979f67e05db1f98c79ef7b08d41b944",
"mode": 420
},
"scripts/ci/run-php-container.sh": {
"sha256": "27b2601a4907737efa9ce157524e36ef0932df97d2d23b515cf65997e4f3725b",
"mode": 493
},
"scripts/ci/setup-php-container.sh": {
"sha256": "db0a276dea94aef70c3873ffc14e0ebf88e5baf4a6145e1a61a281d5835f59e4",
"mode": 493
},
"tests/ci/test_php_container_tls.py": {
"sha256": "9b229ac8400a047bfc6cf60ede16db899298e01b3543b840ab692656c2ef28fb",
"mode": 420
},
"tests/ci/test_php_container_isolation.py": {
"sha256": "821e1c8db3da47ec502efd704044bffb55b744ce7fe1d42c71c367ba0c9e9924",
"mode": 420
}
}
}
}
}
1 change: 1 addition & 0 deletions tests/fixtures/waterline-php82-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
jobs:
build:
needs:
- action-policy
- classify
- frontend
if: ${{ needs.classify.outputs.qualification-class == 'complete' }}
Expand Down
13 changes: 9 additions & 4 deletions tests/test_composer_trust_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,13 +374,12 @@ def setUp(self):
repository = Path(__file__).resolve().parents[1]
self.policy = json.loads((repository / "qualification/policy.json").read_text())
self.document = yaml.safe_load((repository / "tests/fixtures/waterline-php82-build.yml").read_text())
retired = json.loads((repository / "tests/fixtures/retired-writable-runtime-setups.json").read_text())
self.catalog = {"requests": {}, "runtime_setups": {"waterline-php82-build": retired["waterline-php82-build"]}}
self.catalog = json.loads((repository / "qualification/composer-container-trust.json").read_text())
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
self.root = Path(temporary.name)
# Exercise mandatory enumeration using inert historical recipe data.
# This fixture grants no admission in the current production catalog.
# Bind inert bytes to the corrected recipe to exercise the actual target
# policy offline. Retired sources have separate refusal controls.
recipe = self.catalog["runtime_setups"]["waterline-php82-build"]
for name, expected in recipe["files"].items():
path = self.root / name
Expand All @@ -400,6 +399,12 @@ def check(self, document):
def test_proposed_build_enumerates_all_guarded_requests(self):
self.assertEqual(4, len(self.check(self.document)))

def test_proposed_build_accepts_canonical_git_checkout_permissions(self):
recipe = self.catalog["runtime_setups"]["waterline-php82-build"]
for name, expected in recipe["files"].items():
(self.root / name).chmod(0o755 if expected["mode"] & 0o100 else 0o644)
self.assertEqual(4, len(self.check(self.document)))

def test_deleting_every_live_verifier_cannot_disable_enumeration(self):
document = deepcopy(self.document)
steps = document["jobs"]["build"]["steps"]
Expand Down
Loading