diff --git a/examples/policy/README.md b/examples/policy/README.md index 8573b7c6..e708197b 100644 --- a/examples/policy/README.md +++ b/examples/policy/README.md @@ -7,6 +7,7 @@ These templates provide baseline policy packs by risk tier: - `base_high_risk.yaml` - `baseline-highrisk.yaml` (hyphenated alias) - `knowledge_worker_safe.yaml` (reversible-first profile) +- `ci_cd_pipeline.yaml` (CI/CD agent guardrails) Scaffold a baseline file directly from the CLI: @@ -39,6 +40,12 @@ gait policy test examples/policy/base_high_risk.yaml examples/policy/intents/int gait policy test examples/policy/base_high_risk.yaml examples/policy/intents/intent_tainted_egress.json --json gait policy test examples/policy/base_high_risk.yaml examples/policy/intents/intent_delegated_egress_valid.json --json gait policy test examples/policy/base_high_risk.yaml examples/policy/intents/intent_delegated_egress_invalid.json --json + +gait policy test examples/policy/ci_cd_pipeline.yaml examples/policy/intents/intent_ci_read_artifact.json --json +gait policy test examples/policy/ci_cd_pipeline.yaml examples/policy/intents/intent_ci_deploy_staging.json --json +gait policy test examples/policy/ci_cd_pipeline.yaml examples/policy/intents/intent_ci_deploy_production.json --json +gait policy test examples/policy/ci_cd_pipeline.yaml examples/policy/intents/intent_ci_secret_access.json --json +gait policy test examples/policy/ci_cd_pipeline.yaml examples/policy/intents/intent_ci_infra_destroy.json --json ``` Expected verdict matrix: @@ -49,6 +56,11 @@ Expected verdict matrix: - `intent_tainted_egress.json` => `block` (exit `3`) - `intent_delegated_egress_valid.json` => `allow` (exit `0`) - `intent_delegated_egress_invalid.json` => `block` (exit `3`) +- `intent_ci_read_artifact.json` => `allow` (exit `0`) +- `intent_ci_deploy_staging.json` => `allow` (exit `0`) +- `intent_ci_deploy_production.json` => `block` (exit `3`) +- `intent_ci_secret_access.json` => `require_approval` (exit `4`) +- `intent_ci_infra_destroy.json` => `block` (exit `3`) High-risk note: @@ -56,6 +68,7 @@ High-risk note: - `base_high_risk.yaml` requires explicit delegation metadata for high-risk egress writes and blocks tainted external payload flow to network destinations. - `base_high_risk.yaml` and `baseline-highrisk.yaml` include `destructive_budget` defaults to fail-closed once destructive threshold windows are exceeded. - `knowledge_worker_safe.yaml` defaults unknown tools to block, prefers archive/trash actions, and requires explicit break-glass approval for permanent delete paths. +- `ci_cd_pipeline.yaml` governs AI agents operating inside CI/CD pipelines: allows artifact reads and staging deploys, blocks production deploys and infrastructure destruction, requires approval for secret access and infrastructure provisioning. - For runtime checks in hardened mode, evaluate with `--profile oss-prod` and an explicit broker, for example: ```bash diff --git a/examples/policy/ci_cd_pipeline.yaml b/examples/policy/ci_cd_pipeline.yaml new file mode 100644 index 00000000..75bbf7d0 --- /dev/null +++ b/examples/policy/ci_cd_pipeline.yaml @@ -0,0 +1,63 @@ +schema_id: gait.gate.policy +schema_version: 1.0.0 +default_verdict: block +fail_closed: + enabled: true + risk_classes: [critical] + required_fields: [targets, arg_provenance] +rules: + - name: allow-read-build-artifacts + priority: 10 + effect: allow + match: + tool_names: [artifact.read, artifact.download, artifact.list, tool.read] + risk_classes: [low, medium] + reason_codes: [safe_artifact_read] + + - name: allow-staging-deploy + priority: 15 + effect: allow + match: + tool_names: [deploy.apply, deploy.push] + risk_classes: [medium] + workspace_prefixes: [/ci/staging, /deploy/staging] + reason_codes: [staging_deploy_allowed] + + - name: block-production-deploy + priority: 20 + effect: block + match: + tool_names: [deploy.apply, deploy.push] + risk_classes: [critical] + workspace_prefixes: [/ci/production, /deploy/production] + reason_codes: [production_deploy_blocked_in_ci] + violations: [unauthorized_production_deploy] + + - name: require-approval-secret-access + priority: 25 + effect: require_approval + min_approvals: 1 + match: + tool_names: [secret.read, vault.read, secret.rotate] + risk_classes: [high, critical] + reason_codes: [approval_required_for_secret_access] + violations: [secret_access_requires_approval] + + - name: block-infrastructure-mutation + priority: 30 + effect: block + match: + tool_names: [infra.destroy, infra.delete, db.drop, db.truncate] + reason_codes: [infrastructure_mutation_blocked] + violations: [destructive_infrastructure_operation] + + - name: require-approval-infra-create + priority: 35 + effect: require_approval + min_approvals: 2 + require_distinct_approvers: true + match: + tool_names: [infra.create, infra.update] + risk_classes: [high, critical] + reason_codes: [approval_required_for_infrastructure_change] + violations: [infrastructure_change_requires_review] diff --git a/examples/policy/intents/intent_ci_deploy_production.json b/examples/policy/intents/intent_ci_deploy_production.json new file mode 100644 index 00000000..716cf76d --- /dev/null +++ b/examples/policy/intents/intent_ci_deploy_production.json @@ -0,0 +1,32 @@ +{ + "schema_id": "gait.gate.intent_request", + "schema_version": "1.0.0", + "created_at": "2026-03-23T00:00:00Z", + "producer_version": "0.0.0-example", + "tool_name": "deploy.apply", + "args": { + "environment": "production", + "image": "app:sha-abc123" + }, + "targets": [ + { + "kind": "host", + "value": "api.production.example", + "operation": "write", + "endpoint_class": "net.http", + "endpoint_domain": "api.production.example" + } + ], + "arg_provenance": [ + { + "arg_path": "$.image", + "source": "system", + "source_ref": "ci:build_output" + } + ], + "context": { + "identity": "ci-agent", + "workspace": "/ci/production", + "risk_class": "critical" + } +} diff --git a/examples/policy/intents/intent_ci_deploy_staging.json b/examples/policy/intents/intent_ci_deploy_staging.json new file mode 100644 index 00000000..4cef803f --- /dev/null +++ b/examples/policy/intents/intent_ci_deploy_staging.json @@ -0,0 +1,32 @@ +{ + "schema_id": "gait.gate.intent_request", + "schema_version": "1.0.0", + "created_at": "2026-03-23T00:00:00Z", + "producer_version": "0.0.0-example", + "tool_name": "deploy.apply", + "args": { + "environment": "staging", + "image": "app:sha-abc123" + }, + "targets": [ + { + "kind": "host", + "value": "staging.internal.example", + "operation": "write", + "endpoint_class": "net.http", + "endpoint_domain": "staging.internal.example" + } + ], + "arg_provenance": [ + { + "arg_path": "$.image", + "source": "system", + "source_ref": "ci:build_output" + } + ], + "context": { + "identity": "ci-agent", + "workspace": "/ci/staging", + "risk_class": "medium" + } +} diff --git a/examples/policy/intents/intent_ci_infra_destroy.json b/examples/policy/intents/intent_ci_infra_destroy.json new file mode 100644 index 00000000..f3fd4715 --- /dev/null +++ b/examples/policy/intents/intent_ci_infra_destroy.json @@ -0,0 +1,30 @@ +{ + "schema_id": "gait.gate.intent_request", + "schema_version": "1.0.0", + "created_at": "2026-03-23T00:00:00Z", + "producer_version": "0.0.0-example", + "tool_name": "infra.destroy", + "args": { + "resource": "rds-cluster-prod", + "region": "us-east-1" + }, + "targets": [ + { + "kind": "other", + "value": "rds-cluster-prod", + "operation": "delete", + "destructive": true + } + ], + "arg_provenance": [ + { + "arg_path": "$.resource", + "source": "user" + } + ], + "context": { + "identity": "ci-agent", + "workspace": "/ci/workspace", + "risk_class": "high" + } +} diff --git a/examples/policy/intents/intent_ci_read_artifact.json b/examples/policy/intents/intent_ci_read_artifact.json new file mode 100644 index 00000000..076cde36 --- /dev/null +++ b/examples/policy/intents/intent_ci_read_artifact.json @@ -0,0 +1,29 @@ +{ + "schema_id": "gait.gate.intent_request", + "schema_version": "1.0.0", + "created_at": "2026-03-23T00:00:00Z", + "producer_version": "0.0.0-example", + "tool_name": "artifact.read", + "args": { + "artifact_id": "build-output-abc123", + "path": "/ci/artifacts/build.tar.gz" + }, + "targets": [ + { + "kind": "path", + "value": "/ci/artifacts/build.tar.gz", + "operation": "read" + } + ], + "arg_provenance": [ + { + "arg_path": "$.artifact_id", + "source": "system" + } + ], + "context": { + "identity": "ci-agent", + "workspace": "/ci/workspace", + "risk_class": "low" + } +} diff --git a/examples/policy/intents/intent_ci_secret_access.json b/examples/policy/intents/intent_ci_secret_access.json new file mode 100644 index 00000000..dd38ef83 --- /dev/null +++ b/examples/policy/intents/intent_ci_secret_access.json @@ -0,0 +1,30 @@ +{ + "schema_id": "gait.gate.intent_request", + "schema_version": "1.0.0", + "created_at": "2026-03-23T00:00:00Z", + "producer_version": "0.0.0-example", + "tool_name": "secret.read", + "args": { + "secret_name": "DATABASE_URL", + "vault_path": "ci/production/database" + }, + "targets": [ + { + "kind": "other", + "value": "vault://ci/production/database", + "operation": "read" + } + ], + "arg_provenance": [ + { + "arg_path": "$.secret_name", + "source": "system", + "source_ref": "ci:env_config" + } + ], + "context": { + "identity": "ci-agent", + "workspace": "/ci/workspace", + "risk_class": "high" + } +} diff --git a/scripts/policy_compliance_ci.sh b/scripts/policy_compliance_ci.sh index 621752e3..bb4953d7 100755 --- a/scripts/policy_compliance_ci.sh +++ b/scripts/policy_compliance_ci.sh @@ -139,9 +139,15 @@ run_case "template-high-delete" "examples/policy/base_high_risk.yaml" "examples/ run_case "template-high-tainted-egress" "examples/policy/base_high_risk.yaml" "examples/policy/intents/intent_tainted_egress.json" 3 run_case "template-high-delegated-egress-valid" "examples/policy/base_high_risk.yaml" "examples/policy/intents/intent_delegated_egress_valid.json" 0 run_case "template-high-delegated-egress-invalid" "examples/policy/base_high_risk.yaml" "examples/policy/intents/intent_delegated_egress_invalid.json" 3 +run_case "ci-cd-read-artifact" "examples/policy/ci_cd_pipeline.yaml" "examples/policy/intents/intent_ci_read_artifact.json" 0 +run_case "ci-cd-deploy-staging" "examples/policy/ci_cd_pipeline.yaml" "examples/policy/intents/intent_ci_deploy_staging.json" 0 +run_case "ci-cd-deploy-production" "examples/policy/ci_cd_pipeline.yaml" "examples/policy/intents/intent_ci_deploy_production.json" 3 +run_case "ci-cd-secret-access" "examples/policy/ci_cd_pipeline.yaml" "examples/policy/intents/intent_ci_secret_access.json" 4 +run_case "ci-cd-infra-destroy" "examples/policy/ci_cd_pipeline.yaml" "examples/policy/intents/intent_ci_infra_destroy.json" 3 run_validate_case "validate-template-low" "examples/policy/base_low_risk.yaml" 0 run_validate_case "validate-template-medium" "examples/policy/base_medium_risk.yaml" 0 run_validate_case "validate-template-high" "examples/policy/base_high_risk.yaml" 0 +run_validate_case "validate-ci-cd-pipeline" "examples/policy/ci_cd_pipeline.yaml" 0 invalid_policy_path="gait-out/policy_invalid.yaml" cat >"$invalid_policy_path" <<'EOF'