Skip to content
Draft
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
101 changes: 101 additions & 0 deletions contracts/certforge-sdk-capabilities.v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -1770,6 +1770,107 @@
"type": "null"
}
]
},
"project_id": {
"anyOf": [
{
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$",
"type": "string"
},
{
"type": "null"
}
]
},
"target": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"artifact_sha256": {
"anyOf": [
{
"pattern": "^[0-9a-f]{64}$",
"type": "string"
},
{
"type": "null"
}
]
},
"identity_digest": {
"pattern": "^[0-9a-f]{64}$",
"type": "string"
},
"path": {
"anyOf": [
{
"maxLength": 2048,
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
]
},
"ref": {
"anyOf": [
{
"maxLength": 256,
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
]
},
"reference": {
"maxLength": 2048,
"minLength": 1,
"type": "string"
},
"source_commit": {
"anyOf": [
{
"maxLength": 64,
"minLength": 7,
"type": "string"
},
{
"type": "null"
}
]
},
"target_type": {
"pattern": "^(local|git|archive|container|package|deployment|mcp|sdk|cli)$",
"type": "string"
},
"url": {
"anyOf": [
{
"maxLength": 2048,
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"target_type",
"identity_digest",
"reference"
],
"type": "object"
},
{
"type": "null"
}
]
}
},
"required": [
Expand Down
51 changes: 50 additions & 1 deletion docs/RUNTIME_IDENTITY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
# Measured worker runtime identity

## Source-bound project profiles

An operator may select `certforge.runtime.v2` in the same public profile file and
add `project_bindings`. Each binding requires a unique `binding_id`, exact
`tenant_id`, `project_id`, HTTPS `repository`, 40-character `source_commit`, a
nonempty `dependencies` map of repository-relative paths to SHA-256 hashes,
an exact `journey`, and `sandbox` settings using the existing restricted fields.
Image pins, non-root execution and all existing isolation checks remain required.
The operator file is not accepted from target source or the subscriber request.
Installing it still requires independent image qualification and release admission.

The runtime resolver accepts optional `project_id` and `target` together, checks
live project access, and resolves the operator binding for that tenant, project,
repository and revision. It returns the measured environment using the existing
`certforge.runtime.v1` response contract. Clients cannot choose a profile or image.
Other tenants, projects and repositories keep the unchanged default sandbox;
unadmitted revisions of a bound repository fail closed. This also preserves other
repositories when an older App installation shares one subscriber project.

The worker derives its project from the persisted run, selects the same binding,
and verifies the declared environment before acquisition. After acquiring the
exact revision it verifies the actual source commit and each dependency hash,
rejecting missing, oversized, changed, escaping or symlinked files before execution.
The complete operator binding digest is included in the measured environment;
changing dependency expectations therefore invalidates the old commitment.
All reservation, worker, lease, signer and final environment fences remain active.
Selection logs include binding ID, source SHA and binding digest, with no secrets.

Deploy the paired GitHub App resolver change and regenerated SDK schemas only
through the governed release path. An old queued environment must not be silently
rewritten or replayed as a new certification. No service, trust, queue, signing key,
readiness report or production attestation is changed by this source implementation.

Stage the matching API, dispatcher, worker, generated SDK contract and App caller
before activating a source-bound profile. Preserve the previous admitted release,
profile and caller configuration as one rollback unit: a v1-only binary rejects a
v2 profile. Retain queued runs and submission checkpoints without rewriting their
environment or replaying uncertain intents. A source, image or profile change
requires fresh exact-identity evidence; prior readiness and image admission do not
transfer to the new candidate. Connection cleanup retains transaction commit and
rollback while explicitly closing the worker guard and telemetry handles; failure
to remove an owned acceptance workspace still fails its cleanup check.

The `certforge.runtime.v1` contract replaces fixed `certforge-worker-env:*` labels.
An environment commits to the selected manifest digest, exact journey argv and
mandatory rules, executable CertForge package bytes, dependency declarations,
Expand Down Expand Up @@ -116,7 +159,13 @@ secret-field rejection; service/dispatcher/worker identity agreement; and reject
before acquisition, authenticated per-job resolution, caller-image rejection,
and equivalent source/real-built-wheel harness commitments. Subscriber regression
tests additionally verify that changed
journey commitments cannot execute or receive a signed verdict. Full repository
journey commitments cannot execute or receive a signed verdict. Exact-source
project bindings retain the operator-input circuit fence before tenant selection.
An unadmitted source uses the same bounded tenant retry delay as a journey or
environment mismatch, without halting unrelated tenants. The project-binding
tests verify API/worker agreement, altered or missing dependency rejection before
execution, unchanged default isolation and the retained operator classification.
Full repository
and acceptance checks remain required before a release claim.

Host Python and kernel measurements are intentional identity inputs. A host update
Expand Down
2 changes: 1 addition & 1 deletion scripts/register_certforge_sdk_schemas.sql
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ INSERT INTO certforge_sdk_contract(id, input_schema_json, output_schema_json) VA
('echo.certforge.r5.status', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"},"run_id":{"pattern":"^[A-Za-z0-9._-]{1,64}$","type":"string"}},"required":["command","run_id"],"type":"object"}'::jsonb, '{"additionalProperties":false,"properties":{"note":{"type":"string"},"result":{"anyOf":[{"additionalProperties":false,"properties":{"completion_marker":{"type":["string","null"]},"deployment_authorized":{"type":"boolean"},"evidence_run_id":{"type":"string"},"forge_verification":{"additionalProperties":true,"type":"object"},"mode":{"enum":["preflight","full"],"type":"string"},"operator_exit_code":{"type":"integer"},"operator_report":{"additionalProperties":true,"type":"object"},"r5_gate":{"enum":["PASS","BLOCK"],"type":"string"},"release_verdict":{"enum":["NOT_READY"],"type":"string"},"run_outcome":{"type":"string"},"schema":{"type":"string"},"stderr_tail":{"type":"string"}},"required":["schema","mode","evidence_run_id","run_outcome","release_verdict","r5_gate","deployment_authorized","completion_marker","operator_report","forge_verification","operator_exit_code"],"type":"object"},{"type":"null"}]},"run_id":{"type":"string"},"status":{"enum":["RUNNING","COMPLETE","FAILED"],"type":"string"}},"required":["run_id","status"],"type":"object"}'::jsonb),
('echo.certforge.r5.submit_async', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"},"dry_run":{"type":"boolean"},"evidence_run_id":{"pattern":"^[A-Za-z0-9._-]{1,64}$","type":"string"},"evidence_run_nonce":{"maxLength":128,"minLength":16,"type":"string"},"expected_base_model_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"expected_base_model_revision":{"maxLength":128,"minLength":6,"type":"string"},"expected_gs343_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"expected_r2d2_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"expected_registry_revision":{"maxLength":128,"minLength":6,"type":"string"},"expected_registry_snapshot_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"expected_server_build_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"expected_signing_key_id":{"maxLength":128,"minLength":8,"type":"string"},"target_family":{"enum":["gs343","r2d2"],"type":"string"}},"required":["command","target_family","expected_server_build_digest","expected_registry_snapshot_digest","expected_registry_revision","expected_signing_key_id","expected_base_model_digest","expected_base_model_revision","expected_gs343_digest","expected_r2d2_digest","evidence_run_id","evidence_run_nonce"],"type":"object"}'::jsonb, '{"additionalProperties":false,"properties":{"idempotent":{"type":"boolean"},"mode":{"enum":["preflight","full"],"type":"string"},"poll_capability":{"enum":["echo.certforge.r5.status"],"type":"string"},"run_id":{"type":"string"},"status":{"enum":["RESERVED","RUNNING"],"type":"string"}},"required":["run_id","status","mode"],"type":"object"}'::jsonb),
('echo.certforge.run', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"},"run_id":{"pattern":"^[A-Za-z0-9._-]{1,128}$","type":"string"},"tenant":{"pattern":"^[A-Za-z0-9._-]{1,128}$","type":"string"}},"required":["command","run_id","tenant"],"type":"object"}'::jsonb, '{"additionalProperties":false,"properties":{"poll_capability":{"enum":["echo.certforge.status"],"type":"string"},"run_id":{"type":"string"},"sandboxed":{"type":"boolean"},"status":{"enum":["PENDING","CLAIMED"],"type":"string"},"tenant":{"type":"string"}},"required":["run_id","status","tenant","sandboxed","poll_capability"],"type":"object"}'::jsonb),
('echo.certforge.runtime_environment', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"},"journey":{"anyOf":[{"items":{"maxLength":2048,"minLength":1,"pattern":"^[^\\x00]*$","type":"string"},"maxItems":32,"minItems":1,"type":"array"},{"type":"null"}]}},"required":["command"],"type":"object"}'::jsonb, '{"additionalProperties":false,"properties":{"environment":{"additionalProperties":false,"properties":{"adapter_set_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"egress_policy_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"harness_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"model_route_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"os_runtime_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"policy_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"prompt_set_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"runner_image_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"test_plan_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"}},"required":["runner_image_sha256","adapter_set_sha256","test_plan_sha256","policy_sha256","harness_sha256","prompt_set_sha256","model_route_sha256","os_runtime_sha256","egress_policy_sha256"],"type":"object"},"journey":{"anyOf":[{"items":{"maxLength":2048,"minLength":1,"pattern":"^[^\\x00]*$","type":"string"},"type":"array"},{"type":"null"}]},"schema_version":{"const":"certforge.runtime.v1","type":"string"},"submit_environment":{"additionalProperties":false,"properties":{"identity_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"runner_image_digest":{"anyOf":[{"pattern":"^sha256:[0-9a-f]{64}$","type":"string"},{"type":"null"}]}},"required":["identity_digest"],"type":"object"}},"required":["journey","environment","submit_environment"],"type":"object"}'::jsonb),
('echo.certforge.runtime_environment', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"},"journey":{"anyOf":[{"items":{"maxLength":2048,"minLength":1,"pattern":"^[^\\x00]*$","type":"string"},"maxItems":32,"minItems":1,"type":"array"},{"type":"null"}]},"project_id":{"anyOf":[{"pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$","type":"string"},{"type":"null"}]},"target":{"anyOf":[{"additionalProperties":false,"properties":{"artifact_sha256":{"anyOf":[{"pattern":"^[0-9a-f]{64}$","type":"string"},{"type":"null"}]},"identity_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"path":{"anyOf":[{"maxLength":2048,"minLength":1,"type":"string"},{"type":"null"}]},"ref":{"anyOf":[{"maxLength":256,"minLength":1,"type":"string"},{"type":"null"}]},"reference":{"maxLength":2048,"minLength":1,"type":"string"},"source_commit":{"anyOf":[{"maxLength":64,"minLength":7,"type":"string"},{"type":"null"}]},"target_type":{"pattern":"^(local|git|archive|container|package|deployment|mcp|sdk|cli)$","type":"string"},"url":{"anyOf":[{"maxLength":2048,"minLength":1,"type":"string"},{"type":"null"}]}},"required":["target_type","identity_digest","reference"],"type":"object"},{"type":"null"}]}},"required":["command"],"type":"object"}'::jsonb, '{"additionalProperties":false,"properties":{"environment":{"additionalProperties":false,"properties":{"adapter_set_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"egress_policy_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"harness_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"model_route_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"os_runtime_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"policy_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"prompt_set_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"runner_image_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"test_plan_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"}},"required":["runner_image_sha256","adapter_set_sha256","test_plan_sha256","policy_sha256","harness_sha256","prompt_set_sha256","model_route_sha256","os_runtime_sha256","egress_policy_sha256"],"type":"object"},"journey":{"anyOf":[{"items":{"maxLength":2048,"minLength":1,"pattern":"^[^\\x00]*$","type":"string"},"type":"array"},{"type":"null"}]},"schema_version":{"const":"certforge.runtime.v1","type":"string"},"submit_environment":{"additionalProperties":false,"properties":{"identity_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"runner_image_digest":{"anyOf":[{"pattern":"^sha256:[0-9a-f]{64}$","type":"string"},{"type":"null"}]}},"required":["identity_digest"],"type":"object"}},"required":["journey","environment","submit_environment"],"type":"object"}'::jsonb),
('echo.certforge.service_status', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"}},"required":["command"],"type":"object"}'::jsonb, '{"additionalProperties":true,"type":"object"}'::jsonb),
('echo.certforge.status', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"},"run_id":{"type":"string"}},"required":["command","run_id"],"type":"object"}'::jsonb, '{"additionalProperties":true,"type":"object"}'::jsonb),
('echo.certforge.submit', '{"additionalProperties":false,"properties":{"command":{"maxLength":64,"minLength":1,"type":"string"},"environment":{"additionalProperties":false,"properties":{"identity_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"runner_image_digest":{"anyOf":[{"pattern":"^sha256:[0-9a-f]{64}$","type":"string"},{"type":"null"}]}},"required":["identity_digest"],"type":"object"},"idempotency_key":{"maxLength":128,"minLength":8,"type":"string"},"journey":{"anyOf":[{"items":{"type":"string"},"maxItems":32,"type":"array"},{"type":"null"}]},"policy_version":{"maxLength":128,"minLength":1,"type":"string"},"project_id":{"anyOf":[{"pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$","type":"string"},{"type":"null"}]},"target":{"additionalProperties":false,"properties":{"artifact_sha256":{"anyOf":[{"pattern":"^[0-9a-f]{64}$","type":"string"},{"type":"null"}]},"identity_digest":{"pattern":"^[0-9a-f]{64}$","type":"string"},"path":{"anyOf":[{"maxLength":2048,"minLength":1,"type":"string"},{"type":"null"}]},"ref":{"anyOf":[{"maxLength":256,"minLength":1,"type":"string"},{"type":"null"}]},"reference":{"maxLength":2048,"minLength":1,"type":"string"},"source_commit":{"anyOf":[{"maxLength":64,"minLength":7,"type":"string"},{"type":"null"}]},"target_type":{"pattern":"^(local|git|archive|container|package|deployment|mcp|sdk|cli)$","type":"string"},"url":{"anyOf":[{"maxLength":2048,"minLength":1,"type":"string"},{"type":"null"}]}},"required":["target_type","identity_digest","reference"],"type":"object"},"tenant_id":{"maxLength":128,"minLength":1,"type":"string"}},"required":["command","environment","idempotency_key","policy_version","target","tenant_id"],"type":"object"}'::jsonb, '{"additionalProperties":true,"type":"object"}'::jsonb),
Expand Down
2 changes: 1 addition & 1 deletion src/echo_certification_forge/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def _load_certification_environment(runtime: RuntimeProfile | None = None) -> di
"runner_image_digest": "sha256:" + environment.runner_image_sha256,
"adapter_set_sha256": adapter_sha256,
"adapter_execution_profile_sha256": profile_sha256,
"runtime_profile_schema": "certforge.runtime.v1",
"runtime_profile_schema": "certforge.runtime.v2" if runtime.bindings else "certforge.runtime.v1",
"runtime_journey_json": json.dumps(runtime.journey),
"runtime_journey_mode": "operator_pinned" if runtime.journey is not None else "per_job",
}
Expand Down
Loading
Loading