diff --git a/skills/least-privilege-plan/SKILL.md b/skills/least-privilege-plan/SKILL.md new file mode 100644 index 00000000..8691e4f0 --- /dev/null +++ b/skills/least-privilege-plan/SKILL.md @@ -0,0 +1,63 @@ +--- +name: least-privilege-plan +description: Produce a read-only least-privilege grant plan from bounded run history and a declared policy. +source: + type: cli-tool + command: node + args: + - run.mjs + input_mode: stdin + cwd: . + timeout_seconds: 30 +inputs: + run_history_packet: + type: json + required: true + description: Bounded run history containing grants, observed effects, receipt refs, and missing-evidence notes. + policy: + type: json + required: true + description: Declared least-privilege policy with grant metadata, reserved scopes, and review rules. + objective: + type: string + required: false + description: Optional operator intent for the plan. +runx: + category: security + input_resolution: + required: + - run_history_packet + - policy +--- + +# least-privilege-plan + +Use this skill when an operator needs a read-only plan for narrowing granted +authority after one or more runs. The skill compares a bounded run history +packet against a declared policy and emits keep, reduce, revoke, and +needs_human_review recommendations with cited evidence. + +The skill does not mutate grants, write credentials, call provider APIs, or infer +authority from broad task success. Every recommendation cites exact observed +effects, policy inputs, unused scopes, or missing evidence so a reviewer can +apply the plan separately. + +## Inputs + +- `run_history_packet`: bounded JSON with `subject`, `policy_id`, `grants`, + `observed_effects`, `receipt_refs`, and optional `missing_evidence`. +- `policy`: declared JSON policy with grant metadata, reserved scopes, wildcard + rules, and review thresholds. +- `objective`: optional operator intent. + +## Output + +The runner returns JSON with: + +- `plan`: the typed least-privilege plan. +- `recommendations`: one recommendation per grant. +- `evidence_json`: a compact evidence object suitable for external review. +- `report`: a human-readable summary. + +Recommendation actions are exactly `keep`, `reduce`, `revoke`, and +`needs_human_review`. diff --git a/skills/least-privilege-plan/X.yaml b/skills/least-privilege-plan/X.yaml new file mode 100644 index 00000000..e5d0cc70 --- /dev/null +++ b/skills/least-privilege-plan/X.yaml @@ -0,0 +1,227 @@ +skill: least-privilege-plan +version: "0.1.0" + +catalog: + kind: skill + audience: public + visibility: public + role: canonical + +policy: + side_effects: none + grant_mutation: denied + network_during_run: denied + secrets_required: false + filesystem: + read: [] + write: [] + +harness: + cases: + - name: over-broad-grant-plan + runner: default + inputs: + objective: "Prepare a hosted skill for grant reduction before renewal." + policy: + policy_id: runx-policy-demo-v1 + review_rules: + wildcard_reduction_allowed: true + require_human_review_for_denied_secret: true + reserved_grants: + - grant-breakglass + run_history_packet: + subject: skills/sourcey-docs + policy_id: runx-policy-demo-v1 + receipt_refs: + - runx:receipt:sha256:111 + - runx:receipt:sha256:222 + grants: + - grant_id: grant-read-all + scope: repo.read:github/LubuSeb/sourcey-demo/* + declared_policy_ref: policy:repo-read + - grant_id: grant-write-issues + scope: repo.write:github/LubuSeb/sourcey-demo/issues/* + declared_policy_ref: policy:issue-write + - grant_id: grant-delete + scope: repo.delete:github/LubuSeb/sourcey-demo/* + declared_policy_ref: policy:delete + - grant_id: grant-secret-prod + scope: secret.read:prod/* + declared_policy_ref: policy:secret-breakglass + - grant_id: grant-breakglass + scope: incident.breakglass:runx/* + declared_policy_ref: policy:reserved + observed_effects: + - effect_id: e-read-issue + grant_id: grant-read-all + verb: repo.read + resource: github/LubuSeb/sourcey-demo/issues/81 + status: success + receipt_ref: runx:receipt:sha256:111#read_issue + - effect_id: e-write-comment + grant_id: grant-write-issues + verb: repo.write + resource: github/LubuSeb/sourcey-demo/issues/81/comments + status: success + receipt_ref: runx:receipt:sha256:222#comment + - effect_id: e-secret-denied + grant_id: grant-secret-prod + verb: secret.read + resource: prod/frantic-agent-token + status: denied + receipt_ref: runx:receipt:sha256:222#secret_denied + missing_evidence: + - grant_id: grant-secret-prod + reason: "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + expect: + status: sealed + receipt: + schema: runx.receipt.v1 + state: sealed + disposition: closed + reason_code: process_closed + + - name: justified-grant-plan + runner: default + inputs: + objective: "Check that observed usage justifies the current production grant." + policy: + policy_id: runx-policy-justified-v1 + review_rules: + wildcard_reduction_allowed: true + reserved_grants: [] + run_history_packet: + subject: skills/receipt-verifier + policy_id: runx-policy-justified-v1 + receipt_refs: + - runx:receipt:sha256:333 + grants: + - grant_id: grant-receipt-read + scope: receipt.read:runx/receipts/sha256:333 + declared_policy_ref: policy:receipt-read + - grant_id: grant-output-read + scope: artifact.read:runx/outputs/plan.json + declared_policy_ref: policy:artifact-read + observed_effects: + - effect_id: e-receipt-read + grant_id: grant-receipt-read + verb: receipt.read + resource: runx/receipts/sha256:333 + status: success + receipt_ref: runx:receipt:sha256:333#receipt_read + - effect_id: e-output-read + grant_id: grant-output-read + verb: artifact.read + resource: runx/outputs/plan.json + status: success + receipt_ref: runx:receipt:sha256:333#artifact_read + expect: + status: sealed + receipt: + schema: runx.receipt.v1 + state: sealed + disposition: closed + reason_code: process_closed + + - name: missing-grants-fails-closed + runner: default + inputs: + objective: "Reject incomplete run history packets instead of guessing authority." + policy: + policy_id: runx-policy-invalid-v1 + review_rules: + wildcard_reduction_allowed: true + reserved_grants: [] + run_history_packet: + subject: skills/incomplete + policy_id: runx-policy-invalid-v1 + receipt_refs: [] + observed_effects: [] + expect: + status: failure + + - name: invalid-effect-status-fails-closed + runner: default + inputs: + objective: "Reject malformed observed effect status instead of treating it as success." + policy: + policy_id: runx-policy-invalid-status-v1 + review_rules: + wildcard_reduction_allowed: true + reserved_grants: [] + run_history_packet: + subject: skills/status-check + policy_id: runx-policy-invalid-status-v1 + receipt_refs: + - runx:receipt:sha256:badstatus + grants: + - grant_id: grant-read + scope: repo.read:github/LubuSeb/sourcey-demo/* + declared_policy_ref: policy:repo-read + observed_effects: + - effect_id: e-failed + grant_id: grant-read + verb: repo.read + resource: github/LubuSeb/sourcey-demo/issues/81 + status: failed + receipt_ref: runx:receipt:sha256:badstatus#read + expect: + status: failure + + - name: policy-mismatch-fails-closed + runner: default + inputs: + objective: "Reject history packets bound to a different policy id." + policy: + policy_id: runx-policy-declared-v1 + review_rules: + wildcard_reduction_allowed: true + reserved_grants: [] + run_history_packet: + subject: skills/policy-mismatch + policy_id: runx-policy-history-v1 + receipt_refs: + - runx:receipt:sha256:mismatch + grants: + - grant_id: grant-read + scope: repo.read:github/LubuSeb/sourcey-demo/issues/81 + declared_policy_ref: policy:repo-read + observed_effects: + - effect_id: e-read + grant_id: grant-read + verb: repo.read + resource: github/LubuSeb/sourcey-demo/issues/81 + status: success + receipt_ref: runx:receipt:sha256:mismatch#read + expect: + status: failure + +runners: + default: + default: true + type: cli-tool + command: node + input_mode: stdin + args: + - run.mjs + outputs: + plan: object + recommendations: array + evidence_json: object + report: string + artifacts: + wrap_as: least_privilege_plan_packet + packet: runx.security.least_privilege_plan.v1 + inputs: + run_history_packet: + type: json + required: true + description: Bounded run history containing grant ids, scopes, effects, receipt refs, and missing evidence. + policy: + type: json + required: true + description: Declared least-privilege policy. + objective: + type: string + required: false + description: Operator intent for the review. diff --git a/skills/least-privilege-plan/evidence/clean-install.json b/skills/least-privilege-plan/evidence/clean-install.json new file mode 100644 index 00000000..2b5c05bd --- /dev/null +++ b/skills/least-privilege-plan/evidence/clean-install.json @@ -0,0 +1,43 @@ +{ + "status": "success", + "registry": { + "action": "install", + "source": "remote", + "ref": "lubuseb/least-privilege-plan@sha-2ed0e113ff52", + "install": { + "status": "installed", + "destination": "/tmp/runx-least-privilege-plan-clean-install/lubuseb/least-privilege-plan/sha-2ed0e113ff52/SKILL.md", + "skill_name": "least-privilege-plan", + "source": "runx-registry", + "source_label": "runx registry", + "skill_id": "lubuseb/least-privilege-plan", + "version": "sha-2ed0e113ff52", + "digest": "sha256:09c761cf110265d8e5ddc4453fb4cff90cd5b775920557cd4eda384ae20af471", + "profile_digest": "sha256:259c08c1e5725838b9cd593e7a595c883ad10a4ed8d8b2107bfb3cd712977d4e", + "profile_state_path": "/tmp/runx-least-privilege-plan-clean-install/lubuseb/least-privilege-plan/sha-2ed0e113ff52/.runx/profile.json", + "runner_names": [ + "default" + ], + "trust_tier": "community" + }, + "receipt_metadata": { + "destination": "/tmp/runx-least-privilege-plan-clean-install/lubuseb/least-privilege-plan/sha-2ed0e113ff52/SKILL.md", + "digest": "sha256:09c761cf110265d8e5ddc4453fb4cff90cd5b775920557cd4eda384ae20af471", + "install_count": 1, + "package_digest": "a25cc87d7f6078709b7f7af1e7485d67257b428d3d26a895e2395ab7bcb4867e", + "profile_digest": "sha256:259c08c1e5725838b9cd593e7a595c883ad10a4ed8d8b2107bfb3cd712977d4e", + "publisher": { + "display_name": "LubuSeb", + "handle": "lubuseb", + "id": "user_53f00ae7ec2363e37ac6ff68", + "kind": "user" + }, + "ref": "lubuseb/least-privilege-plan@sha-2ed0e113ff52", + "skill_id": "lubuseb/least-privilege-plan", + "source_label": "runx registry", + "status": "installed", + "trust_tier": "community", + "version": "sha-2ed0e113ff52" + } + } +} diff --git a/skills/least-privilege-plan/evidence/dogfood-output.json b/skills/least-privilege-plan/evidence/dogfood-output.json new file mode 100644 index 00000000..0137db7b --- /dev/null +++ b/skills/least-privilege-plan/evidence/dogfood-output.json @@ -0,0 +1,1341 @@ +{ + "closure": { + "closed_at": "2026-06-22T14:38:16.608Z", + "disposition": "closed", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "execution": { + "exit_code": 0, + "skill_claim": { + "evidence_json": { + "artifact": "least-privilege-plan", + "observations": { + "grant_ids": [ + "grant-read-all", + "grant-write-issues", + "grant-delete", + "grant-secret-prod", + "grant-breakglass" + ], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "grant_id": "grant-read-all", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + }, + { + "effect_id": "e-write-comment", + "grant_id": "grant-write-issues", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + }, + { + "effect_id": "e-secret-denied", + "grant_id": "grant-secret-prod", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_digest": "sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9", + "policy_id": "runx-policy-demo-v1", + "receipt_refs": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "recommendations": [ + { + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "recommendation": "reduce" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "recommendation": "reduce" + }, + { + "evidence_refs": [], + "grant_id": "grant-delete", + "proposed_scope": null, + "recommendation": "revoke" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "proposed_scope": null, + "recommendation": "needs_human_review" + }, + { + "evidence_refs": [], + "grant_id": "grant-breakglass", + "proposed_scope": null, + "recommendation": "keep" + } + ], + "run_history_digest": "sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965", + "subject": "skills/sourcey-docs", + "unused_scopes": [ + { + "grant_id": "grant-delete", + "scope": "repo.delete:github/LubuSeb/sourcey-demo/*" + } + ] + }, + "schema": "frantic.delivery.evidence.v1" + }, + "plan": { + "objective": "Dogfood least privilege plan for Frantic bounty 37.", + "policy_id": "runx-policy-demo-v1", + "proposed_grants": [ + { + "grant_id": "grant-read-all", + "scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "source": "reduce" + }, + { + "grant_id": "grant-write-issues", + "scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "source": "reduce" + }, + { + "grant_id": "grant-breakglass", + "scope": "incident.breakglass:runx/*", + "source": "keep" + } + ], + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "safeguards": { + "mutates_grants": false, + "network_required": false, + "read_only": true, + "secrets_required": false + }, + "schema": "runx.security.least_privilege_plan.v1", + "source_receipts": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "status": "needs_human_review", + "subject": "skills/sourcey-docs", + "summary": { + "grant_count": 5, + "observed_effect_count": 3, + "recommendation_counts": { + "keep": 1, + "needs_human_review": 1, + "reduce": 2, + "revoke": 1 + } + } + }, + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "report": "# least-privilege-plan report\n\nSubject: skills/sourcey-docs\nPolicy: runx-policy-demo-v1\nStatus: needs_human_review\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\n\n## Recommendations\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\n\nRead-only: true; mutates grants: false." + }, + "stderr": "", + "stdout": "{\n \"plan\": {\n \"schema\": \"runx.security.least_privilege_plan.v1\",\n \"status\": \"needs_human_review\",\n \"subject\": \"skills/sourcey-docs\",\n \"objective\": \"Dogfood least privilege plan for Frantic bounty 37.\",\n \"policy_id\": \"runx-policy-demo-v1\",\n \"source_receipts\": [\n \"runx:receipt:sha256:111\",\n \"runx:receipt:sha256:222\"\n ],\n \"recommendations\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"current_scope\": \"repo.read:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-read-issue\",\n \"verb\": \"repo.read\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:111#read_issue\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:repo-read\"\n ],\n \"unused_scopes\": [\n \"repo.read:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:111#read_issue\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"current_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-write-comment\",\n \"verb\": \"repo.write\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:222#comment\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:issue-write\"\n ],\n \"unused_scopes\": [\n \"repo.write:github/LubuSeb/sourcey-demo/issues/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#comment\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-delete\",\n \"current_scope\": \"repo.delete:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"revoke\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:delete\"\n ],\n \"unused_scopes\": [\n \"repo.delete:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"No successful observed effect exercised this grant in the supplied run history.\",\n \"risk_notes\": [\n \"Revocation is safe only for the supplied evidence window; future workloads may require new authority.\"\n ]\n },\n {\n \"grant_id\": \"grant-secret-prod\",\n \"current_scope\": \"secret.read:prod/*\",\n \"recommendation\": \"needs_human_review\",\n \"proposed_scope\": null,\n \"observed_effects\": [\n {\n \"effect_id\": \"e-secret-denied\",\n \"verb\": \"secret.read\",\n \"resource\": \"prod/frantic-agent-token\",\n \"status\": \"denied\",\n \"receipt_ref\": \"runx:receipt:sha256:222#secret_denied\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:secret-breakglass\"\n ],\n \"unused_scopes\": [\n \"secret.read:prod/*\"\n ],\n \"missing_evidence\": [\n \"Only a denied check exists; policy owner must decide whether this reserved secret scope is still required.\"\n ],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#secret_denied\"\n ],\n \"rationale\": \"The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.\",\n \"risk_notes\": [\n \"Do not revoke or reduce this grant automatically until the missing evidence is resolved.\"\n ]\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"current_scope\": \"incident.breakglass:runx/*\",\n \"recommendation\": \"keep\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:reserved\"\n ],\n \"unused_scopes\": [\n \"incident.breakglass:runx/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"The declared policy marks this grant as reserved or break-glass authority.\",\n \"risk_notes\": [\n \"Reserved grants remain broad by policy; schedule a separate human review if that posture changes.\"\n ]\n }\n ],\n \"proposed_grants\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"source\": \"reduce\"\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"source\": \"reduce\"\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"scope\": \"incident.breakglass:runx/*\",\n \"source\": \"keep\"\n }\n ],\n \"summary\": {\n \"grant_count\": 5,\n \"observed_effect_count\": 3,\n \"recommendation_counts\": {\n \"keep\": 1,\n \"reduce\": 2,\n \"revoke\": 1,\n \"needs_human_review\": 1\n }\n },\n \"safeguards\": {\n \"read_only\": true,\n \"mutates_grants\": false,\n \"network_required\": false,\n \"secrets_required\": false\n }\n },\n \"recommendations\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"current_scope\": \"repo.read:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-read-issue\",\n \"verb\": \"repo.read\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:111#read_issue\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:repo-read\"\n ],\n \"unused_scopes\": [\n \"repo.read:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:111#read_issue\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"current_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-write-comment\",\n \"verb\": \"repo.write\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:222#comment\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:issue-write\"\n ],\n \"unused_scopes\": [\n \"repo.write:github/LubuSeb/sourcey-demo/issues/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#comment\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-delete\",\n \"current_scope\": \"repo.delete:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"revoke\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:delete\"\n ],\n \"unused_scopes\": [\n \"repo.delete:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"No successful observed effect exercised this grant in the supplied run history.\",\n \"risk_notes\": [\n \"Revocation is safe only for the supplied evidence window; future workloads may require new authority.\"\n ]\n },\n {\n \"grant_id\": \"grant-secret-prod\",\n \"current_scope\": \"secret.read:prod/*\",\n \"recommendation\": \"needs_human_review\",\n \"proposed_scope\": null,\n \"observed_effects\": [\n {\n \"effect_id\": \"e-secret-denied\",\n \"verb\": \"secret.read\",\n \"resource\": \"prod/frantic-agent-token\",\n \"status\": \"denied\",\n \"receipt_ref\": \"runx:receipt:sha256:222#secret_denied\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:secret-breakglass\"\n ],\n \"unused_scopes\": [\n \"secret.read:prod/*\"\n ],\n \"missing_evidence\": [\n \"Only a denied check exists; policy owner must decide whether this reserved secret scope is still required.\"\n ],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#secret_denied\"\n ],\n \"rationale\": \"The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.\",\n \"risk_notes\": [\n \"Do not revoke or reduce this grant automatically until the missing evidence is resolved.\"\n ]\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"current_scope\": \"incident.breakglass:runx/*\",\n \"recommendation\": \"keep\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:reserved\"\n ],\n \"unused_scopes\": [\n \"incident.breakglass:runx/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"The declared policy marks this grant as reserved or break-glass authority.\",\n \"risk_notes\": [\n \"Reserved grants remain broad by policy; schedule a separate human review if that posture changes.\"\n ]\n }\n ],\n \"evidence_json\": {\n \"schema\": \"frantic.delivery.evidence.v1\",\n \"artifact\": \"least-privilege-plan\",\n \"observations\": {\n \"policy_id\": \"runx-policy-demo-v1\",\n \"policy_digest\": \"sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9\",\n \"run_history_digest\": \"sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965\",\n \"subject\": \"skills/sourcey-docs\",\n \"grant_ids\": [\n \"grant-read-all\",\n \"grant-write-issues\",\n \"grant-delete\",\n \"grant-secret-prod\",\n \"grant-breakglass\"\n ],\n \"observed_effects\": [\n {\n \"effect_id\": \"e-read-issue\",\n \"grant_id\": \"grant-read-all\",\n \"verb\": \"repo.read\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:111#read_issue\"\n },\n {\n \"effect_id\": \"e-write-comment\",\n \"grant_id\": \"grant-write-issues\",\n \"verb\": \"repo.write\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:222#comment\"\n },\n {\n \"effect_id\": \"e-secret-denied\",\n \"grant_id\": \"grant-secret-prod\",\n \"verb\": \"secret.read\",\n \"resource\": \"prod/frantic-agent-token\",\n \"status\": \"denied\",\n \"receipt_ref\": \"runx:receipt:sha256:222#secret_denied\"\n }\n ],\n \"unused_scopes\": [\n {\n \"grant_id\": \"grant-delete\",\n \"scope\": \"repo.delete:github/LubuSeb/sourcey-demo/*\"\n }\n ],\n \"recommendations\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"evidence_refs\": [\n \"runx:receipt:sha256:111#read_issue\"\n ]\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#comment\"\n ]\n },\n {\n \"grant_id\": \"grant-delete\",\n \"recommendation\": \"revoke\",\n \"proposed_scope\": null,\n \"evidence_refs\": []\n },\n {\n \"grant_id\": \"grant-secret-prod\",\n \"recommendation\": \"needs_human_review\",\n \"proposed_scope\": null,\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#secret_denied\"\n ]\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"recommendation\": \"keep\",\n \"proposed_scope\": null,\n \"evidence_refs\": []\n }\n ],\n \"receipt_refs\": [\n \"runx:receipt:sha256:111\",\n \"runx:receipt:sha256:222\"\n ]\n }\n },\n \"report\": \"# least-privilege-plan report\\n\\nSubject: skills/sourcey-docs\\nPolicy: runx-policy-demo-v1\\nStatus: needs_human_review\\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\\n\\n## Recommendations\\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\\n\\nRead-only: true; mutates grants: false.\"\n}\n", + "structured_output": { + "evidence_json": { + "artifact": "least-privilege-plan", + "observations": { + "grant_ids": [ + "grant-read-all", + "grant-write-issues", + "grant-delete", + "grant-secret-prod", + "grant-breakglass" + ], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "grant_id": "grant-read-all", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + }, + { + "effect_id": "e-write-comment", + "grant_id": "grant-write-issues", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + }, + { + "effect_id": "e-secret-denied", + "grant_id": "grant-secret-prod", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_digest": "sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9", + "policy_id": "runx-policy-demo-v1", + "receipt_refs": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "recommendations": [ + { + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "recommendation": "reduce" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "recommendation": "reduce" + }, + { + "evidence_refs": [], + "grant_id": "grant-delete", + "proposed_scope": null, + "recommendation": "revoke" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "proposed_scope": null, + "recommendation": "needs_human_review" + }, + { + "evidence_refs": [], + "grant_id": "grant-breakglass", + "proposed_scope": null, + "recommendation": "keep" + } + ], + "run_history_digest": "sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965", + "subject": "skills/sourcey-docs", + "unused_scopes": [ + { + "grant_id": "grant-delete", + "scope": "repo.delete:github/LubuSeb/sourcey-demo/*" + } + ] + }, + "schema": "frantic.delivery.evidence.v1" + }, + "plan": { + "objective": "Dogfood least privilege plan for Frantic bounty 37.", + "policy_id": "runx-policy-demo-v1", + "proposed_grants": [ + { + "grant_id": "grant-read-all", + "scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "source": "reduce" + }, + { + "grant_id": "grant-write-issues", + "scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "source": "reduce" + }, + { + "grant_id": "grant-breakglass", + "scope": "incident.breakglass:runx/*", + "source": "keep" + } + ], + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "safeguards": { + "mutates_grants": false, + "network_required": false, + "read_only": true, + "secrets_required": false + }, + "schema": "runx.security.least_privilege_plan.v1", + "source_receipts": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "status": "needs_human_review", + "subject": "skills/sourcey-docs", + "summary": { + "grant_count": 5, + "observed_effect_count": 3, + "recommendation_counts": { + "keep": 1, + "needs_human_review": 1, + "reduce": 2, + "revoke": 1 + } + } + }, + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "report": "# least-privilege-plan report\n\nSubject: skills/sourcey-docs\nPolicy: runx-policy-demo-v1\nStatus: needs_human_review\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\n\n## Recommendations\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\n\nRead-only: true; mutates grants: false." + } + }, + "payload": { + "evidence_json": { + "artifact": "least-privilege-plan", + "observations": { + "grant_ids": [ + "grant-read-all", + "grant-write-issues", + "grant-delete", + "grant-secret-prod", + "grant-breakglass" + ], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "grant_id": "grant-read-all", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + }, + { + "effect_id": "e-write-comment", + "grant_id": "grant-write-issues", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + }, + { + "effect_id": "e-secret-denied", + "grant_id": "grant-secret-prod", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_digest": "sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9", + "policy_id": "runx-policy-demo-v1", + "receipt_refs": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "recommendations": [ + { + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "recommendation": "reduce" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "recommendation": "reduce" + }, + { + "evidence_refs": [], + "grant_id": "grant-delete", + "proposed_scope": null, + "recommendation": "revoke" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "proposed_scope": null, + "recommendation": "needs_human_review" + }, + { + "evidence_refs": [], + "grant_id": "grant-breakglass", + "proposed_scope": null, + "recommendation": "keep" + } + ], + "run_history_digest": "sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965", + "subject": "skills/sourcey-docs", + "unused_scopes": [ + { + "grant_id": "grant-delete", + "scope": "repo.delete:github/LubuSeb/sourcey-demo/*" + } + ] + }, + "schema": "frantic.delivery.evidence.v1" + }, + "plan": { + "objective": "Dogfood least privilege plan for Frantic bounty 37.", + "policy_id": "runx-policy-demo-v1", + "proposed_grants": [ + { + "grant_id": "grant-read-all", + "scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "source": "reduce" + }, + { + "grant_id": "grant-write-issues", + "scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "source": "reduce" + }, + { + "grant_id": "grant-breakglass", + "scope": "incident.breakglass:runx/*", + "source": "keep" + } + ], + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "safeguards": { + "mutates_grants": false, + "network_required": false, + "read_only": true, + "secrets_required": false + }, + "schema": "runx.security.least_privilege_plan.v1", + "source_receipts": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "status": "needs_human_review", + "subject": "skills/sourcey-docs", + "summary": { + "grant_count": 5, + "observed_effect_count": 3, + "recommendation_counts": { + "keep": 1, + "needs_human_review": 1, + "reduce": 2, + "revoke": 1 + } + } + }, + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "report": "# least-privilege-plan report\n\nSubject: skills/sourcey-docs\nPolicy: runx-policy-demo-v1\nStatus: needs_human_review\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\n\n## Recommendations\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\n\nRead-only: true; mutates grants: false." + }, + "receipt": { + "acts": [ + { + "artifact_refs": [], + "closure": { + "closed_at": "2026-06-22T14:38:16.608Z", + "disposition": "closed", + "reason_code": "process_exit", + "summary": "cli-tool exited successfully" + }, + "criterion_bindings": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "form": "observation", + "id": "act_default", + "intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Runtime graph execution was admitted by the local harness", + "purpose": "Run graph step default", + "success_criteria": [ + { + "criterion_id": "process_exit", + "required": true, + "statement": "cli-tool exits successfully" + } + ] + }, + "source_refs": [], + "summary": "Executed graph step default", + "target_refs": [] + } + ], + "authority": { + "actor_ref": { + "type": "principal", + "uri": "runx:principal:local_runtime" + }, + "attenuation": { + "parent_authority_ref": null, + "subset_proof": null + }, + "authority_proof_refs": [], + "enforcement": { + "profile_hash": "sha256:runtime-skeleton-enforcement", + "redaction_refs": [], + "setup_refs": [], + "teardown_refs": [] + }, + "grant_refs": [], + "scope_refs": [], + "terms": [] + }, + "canonicalization": "runx.receipt.c14n.v1", + "created_at": "2026-06-22T14:38:16.608Z", + "decisions": [ + { + "artifact_refs": [], + "choice": "open", + "closure": null, + "decision_id": "dec_default", + "inputs": { + "opportunity_refs": [], + "selection_ref": null, + "signal_refs": [], + "target_ref": null + }, + "justification": { + "evidence_refs": [], + "summary": "runtime graph planner selected this node" + }, + "proposed_intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Local graph execution requested this node", + "purpose": "Open runtime node default", + "success_criteria": [] + }, + "selected_act_id": "act_default", + "selected_harness_ref": null + } + ], + "digest": "sha256:53135f35bf5f06deb443db6c5cbc2c7028d801a45e914de76d290b534a637da3", + "id": "sha256:cfceaadb4aee0c212b40c4eb2a554f5df3a6e5fbf0ea0df7538efc627e839a15", + "idempotency": { + "content_hash": "sha256:run_default_54e783e6e467-default-content", + "intent_key": "sha256:run_default_54e783e6e467-default-intent", + "trigger_fingerprint": "sha256:run_default_54e783e6e467-default-trigger" + }, + "issuer": { + "kid": "local:bountybar-frantic-runx-22-20260618192655", + "public_key_sha256": "sha256:afae74faf1b1b104b27d788bee2dd0982052af89a1ae30b3282f1a14b0707871", + "type": "hosted" + }, + "lineage": { + "children": [], + "sync": [] + }, + "schema": "runx.receipt.v1", + "seal": { + "closed_at": "2026-06-22T14:38:16.608Z", + "criteria": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "disposition": "closed", + "last_observed_at": "2026-06-22T14:38:16.608Z", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "signals": [], + "signature": { + "alg": "Ed25519", + "value": "base64:zMqSnStJB5sXWbNMpqXwZwRd3sjXvbgmBzqaessSZXONA62tyUgaqa5t2g3gmitDUbCki9jc-92XhMBy7pvsBQ" + }, + "subject": { + "commitments": [], + "kind": "skill", + "ref": { + "type": "harness", + "uri": "hrn_run_default_54e783e6e467_default" + } + } + }, + "receipt_id": "sha256:cfceaadb4aee0c212b40c4eb2a554f5df3a6e5fbf0ea0df7538efc627e839a15", + "run_id": "run_default_54e783e6e467", + "schema": "runx.skill_run.v1", + "skill_name": "least-privilege-plan", + "status": "sealed" +} diff --git a/skills/least-privilege-plan/evidence/dogfood-receipts-linux.tgz b/skills/least-privilege-plan/evidence/dogfood-receipts-linux.tgz new file mode 100644 index 00000000..f9023ecf Binary files /dev/null and b/skills/least-privilege-plan/evidence/dogfood-receipts-linux.tgz differ diff --git a/skills/least-privilege-plan/evidence/evidence.json b/skills/least-privilege-plan/evidence/evidence.json new file mode 100644 index 00000000..ae9549e4 --- /dev/null +++ b/skills/least-privilege-plan/evidence/evidence.json @@ -0,0 +1,93 @@ +{ + "schema": "frantic.delivery.evidence.v1", + "summary": "least-privilege-plan was published as a hosted runx skill, installed from the registry into a clean directory, harnessed from the installed package, dogfooded on a bounded over-broad grant packet, and verified with a sealed production-mode runx receipt.", + "artifact": "least-privilege-plan", + "package": { + "owner": "lubuseb", + "name": "least-privilege-plan", + "version": "sha-2ed0e113ff52", + "registry_ref": "lubuseb/least-privilege-plan@sha-2ed0e113ff52", + "public_url": "https://runx.ai/x/lubuseb/least-privilege-plan@sha-2ed0e113ff52", + "digest": "09c761cf110265d8e5ddc4453fb4cff90cd5b775920557cd4eda384ae20af471", + "profile_digest": "259c08c1e5725838b9cd593e7a595c883ad10a4ed8d8b2107bfb3cd712977d4e" + }, + "source": { + "pr_url": "https://github.com/runxhq/runx/pull/118", + "source_url": "https://github.com/LubuSeb/runx/tree/lubu/least-privilege-plan-37", + "x_yaml": "https://raw.githubusercontent.com/LubuSeb/runx/lubu/least-privilege-plan-37/skills/least-privilege-plan/X.yaml", + "skill_md": "https://raw.githubusercontent.com/LubuSeb/runx/lubu/least-privilege-plan-37/skills/least-privilege-plan/SKILL.md" + }, + "runtime": { + "runx_version": "runx-cli 0.6.13", + "receipt_ref": "runx:receipt:sha256:434a5446b2f7d85b35a2ff9ec70ba48d25c8bf06b8cb64f0f79ff4a576f33d77", + "receipt_id": "sha256:434a5446b2f7d85b35a2ff9ec70ba48d25c8bf06b8cb64f0f79ff4a576f33d77", + "verify_verdict": "valid", + "signature_mode": "production" + }, + "observations": [ + { + "name": "published_registry_package", + "status": "passed", + "detail": "runx registry publish completed successfully for lubuseb/least-privilege-plan@sha-2ed0e113ff52 on https://api.runx.ai.", + "evidence_ref": "registry-publish.json" + }, + { + "name": "registry_read", + "status": "passed", + "detail": "runx registry read resolved the same owner, name, version, digest, profile digest, publisher handle, install command, and run command.", + "evidence_ref": "registry-read.json" + }, + { + "name": "clean_install", + "status": "passed", + "detail": "runx add installed the published package into /tmp/runx-least-privilege-plan-clean-install with digest sha256:09c761cf110265d8e5ddc4453fb4cff90cd5b775920557cd4eda384ae20af471.", + "evidence_ref": "clean-install.json" + }, + { + "name": "hosted_harness", + "status": "passed", + "detail": "The installed registry package passed over-broad-grant-plan, justified-grant-plan, missing-grants-fails-closed, invalid-effect-status-fails-closed, and policy-mismatch-fails-closed harness cases.", + "evidence_ref": "hosted-harness.json" + }, + { + "name": "hosted_harness_receipts_verified", + "status": "passed", + "detail": "All hosted harness receipts verified with production-mode signatures and no findings.", + "evidence_ref": "hosted-harness-verification.json" + }, + { + "name": "dogfood_run", + "status": "sealed", + "detail": "runx skill lubuseb/least-privilege-plan@sha-2ed0e113ff52 produced keep, reduce, revoke, and needs_human_review recommendations for the over-broad fixture.", + "evidence_ref": "hosted-dogfood-output.json" + }, + { + "name": "dogfood_receipt_verified", + "status": "passed", + "detail": "runx verify accepted receipt sha256:434a5446b2f7d85b35a2ff9ec70ba48d25c8bf06b8cb64f0f79ff4a576f33d77 with valid=true and no findings.", + "evidence_ref": "hosted-verification.json" + }, + { + "name": "recommendation_contract", + "status": "passed", + "detail": "Typed output includes keep, reduce, revoke, and needs_human_review; every recommendation cites observed effects, policy refs, unused scopes, or missing evidence.", + "evidence_ref": "hosted-dogfood-output.json" + }, + { + "name": "read_only_behavior", + "status": "passed", + "detail": "The runner reads JSON inputs, computes in memory, performs no provider calls, requires no secrets, and emits structured stdout only.", + "evidence_ref": "run.mjs" + } + ], + "commands": [ + "npx --yes @runxhq/cli@latest --version", + "npx --yes @runxhq/cli@latest harness /mnt/f/BountyBar/repos/runx/skills/least-privilege-plan --json", + "npx --yes @runxhq/cli@latest registry publish /mnt/f/BountyBar/repos/runx/skills/least-privilege-plan/SKILL.md --registry https://api.runx.ai --json", + "npx --yes @runxhq/cli@latest registry read lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai --json", + "npx --yes @runxhq/cli@latest add lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai --to /tmp/runx-least-privilege-plan-clean-install --json", + "npx --yes @runxhq/cli@latest harness /tmp/runx-least-privilege-plan-clean-install/lubuseb/least-privilege-plan/sha-2ed0e113ff52 --json", + "npx --yes @runxhq/cli@latest skill lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai --input-json run_history_packet= --input-json policy= --json", + "npx --yes @runxhq/cli@latest verify --receipt-dir /tmp/runx-least-privilege-plan-hosted-dogfood-receipts --json" + ] +} diff --git a/skills/least-privilege-plan/evidence/hosted-dogfood-output.json b/skills/least-privilege-plan/evidence/hosted-dogfood-output.json new file mode 100644 index 00000000..9ecb3e6d --- /dev/null +++ b/skills/least-privilege-plan/evidence/hosted-dogfood-output.json @@ -0,0 +1,1352 @@ +{ + "closure": { + "closed_at": "2026-06-22T14:38:42.900Z", + "disposition": "closed", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "execution": { + "exit_code": 0, + "skill_claim": { + "evidence_json": { + "artifact": "least-privilege-plan", + "observations": { + "grant_ids": [ + "grant-read-all", + "grant-write-issues", + "grant-delete", + "grant-secret-prod", + "grant-breakglass" + ], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "grant_id": "grant-read-all", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + }, + { + "effect_id": "e-write-comment", + "grant_id": "grant-write-issues", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + }, + { + "effect_id": "e-secret-denied", + "grant_id": "grant-secret-prod", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_digest": "sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9", + "policy_id": "runx-policy-demo-v1", + "receipt_refs": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "recommendations": [ + { + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "recommendation": "reduce" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "recommendation": "reduce" + }, + { + "evidence_refs": [], + "grant_id": "grant-delete", + "proposed_scope": null, + "recommendation": "revoke" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "proposed_scope": null, + "recommendation": "needs_human_review" + }, + { + "evidence_refs": [], + "grant_id": "grant-breakglass", + "proposed_scope": null, + "recommendation": "keep" + } + ], + "run_history_digest": "sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965", + "subject": "skills/sourcey-docs", + "unused_scopes": [ + { + "grant_id": "grant-delete", + "scope": "repo.delete:github/LubuSeb/sourcey-demo/*" + } + ] + }, + "schema": "frantic.delivery.evidence.v1" + }, + "plan": { + "objective": "Hosted dogfood least privilege plan for Frantic bounty 37.", + "policy_id": "runx-policy-demo-v1", + "proposed_grants": [ + { + "grant_id": "grant-read-all", + "scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "source": "reduce" + }, + { + "grant_id": "grant-write-issues", + "scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "source": "reduce" + }, + { + "grant_id": "grant-breakglass", + "scope": "incident.breakglass:runx/*", + "source": "keep" + } + ], + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "safeguards": { + "mutates_grants": false, + "network_required": false, + "read_only": true, + "secrets_required": false + }, + "schema": "runx.security.least_privilege_plan.v1", + "source_receipts": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "status": "needs_human_review", + "subject": "skills/sourcey-docs", + "summary": { + "grant_count": 5, + "observed_effect_count": 3, + "recommendation_counts": { + "keep": 1, + "needs_human_review": 1, + "reduce": 2, + "revoke": 1 + } + } + }, + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "report": "# least-privilege-plan report\n\nSubject: skills/sourcey-docs\nPolicy: runx-policy-demo-v1\nStatus: needs_human_review\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\n\n## Recommendations\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\n\nRead-only: true; mutates grants: false." + }, + "stderr": "", + "stdout": "{\n \"plan\": {\n \"schema\": \"runx.security.least_privilege_plan.v1\",\n \"status\": \"needs_human_review\",\n \"subject\": \"skills/sourcey-docs\",\n \"objective\": \"Hosted dogfood least privilege plan for Frantic bounty 37.\",\n \"policy_id\": \"runx-policy-demo-v1\",\n \"source_receipts\": [\n \"runx:receipt:sha256:111\",\n \"runx:receipt:sha256:222\"\n ],\n \"recommendations\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"current_scope\": \"repo.read:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-read-issue\",\n \"verb\": \"repo.read\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:111#read_issue\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:repo-read\"\n ],\n \"unused_scopes\": [\n \"repo.read:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:111#read_issue\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"current_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-write-comment\",\n \"verb\": \"repo.write\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:222#comment\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:issue-write\"\n ],\n \"unused_scopes\": [\n \"repo.write:github/LubuSeb/sourcey-demo/issues/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#comment\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-delete\",\n \"current_scope\": \"repo.delete:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"revoke\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:delete\"\n ],\n \"unused_scopes\": [\n \"repo.delete:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"No successful observed effect exercised this grant in the supplied run history.\",\n \"risk_notes\": [\n \"Revocation is safe only for the supplied evidence window; future workloads may require new authority.\"\n ]\n },\n {\n \"grant_id\": \"grant-secret-prod\",\n \"current_scope\": \"secret.read:prod/*\",\n \"recommendation\": \"needs_human_review\",\n \"proposed_scope\": null,\n \"observed_effects\": [\n {\n \"effect_id\": \"e-secret-denied\",\n \"verb\": \"secret.read\",\n \"resource\": \"prod/frantic-agent-token\",\n \"status\": \"denied\",\n \"receipt_ref\": \"runx:receipt:sha256:222#secret_denied\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:secret-breakglass\"\n ],\n \"unused_scopes\": [\n \"secret.read:prod/*\"\n ],\n \"missing_evidence\": [\n \"Only a denied check exists; policy owner must decide whether this reserved secret scope is still required.\"\n ],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#secret_denied\"\n ],\n \"rationale\": \"The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.\",\n \"risk_notes\": [\n \"Do not revoke or reduce this grant automatically until the missing evidence is resolved.\"\n ]\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"current_scope\": \"incident.breakglass:runx/*\",\n \"recommendation\": \"keep\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:reserved\"\n ],\n \"unused_scopes\": [\n \"incident.breakglass:runx/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"The declared policy marks this grant as reserved or break-glass authority.\",\n \"risk_notes\": [\n \"Reserved grants remain broad by policy; schedule a separate human review if that posture changes.\"\n ]\n }\n ],\n \"proposed_grants\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"source\": \"reduce\"\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"source\": \"reduce\"\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"scope\": \"incident.breakglass:runx/*\",\n \"source\": \"keep\"\n }\n ],\n \"summary\": {\n \"grant_count\": 5,\n \"observed_effect_count\": 3,\n \"recommendation_counts\": {\n \"keep\": 1,\n \"reduce\": 2,\n \"revoke\": 1,\n \"needs_human_review\": 1\n }\n },\n \"safeguards\": {\n \"read_only\": true,\n \"mutates_grants\": false,\n \"network_required\": false,\n \"secrets_required\": false\n }\n },\n \"recommendations\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"current_scope\": \"repo.read:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-read-issue\",\n \"verb\": \"repo.read\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:111#read_issue\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:repo-read\"\n ],\n \"unused_scopes\": [\n \"repo.read:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:111#read_issue\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"current_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/*\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"observed_effects\": [\n {\n \"effect_id\": \"e-write-comment\",\n \"verb\": \"repo.write\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:222#comment\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:issue-write\"\n ],\n \"unused_scopes\": [\n \"repo.write:github/LubuSeb/sourcey-demo/issues/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#comment\"\n ],\n \"rationale\": \"Successful observed effects fit a narrower resource path than the current wildcard grant.\",\n \"risk_notes\": [\n \"The reduced scope preserves only the cited resources from this evidence packet.\"\n ]\n },\n {\n \"grant_id\": \"grant-delete\",\n \"current_scope\": \"repo.delete:github/LubuSeb/sourcey-demo/*\",\n \"recommendation\": \"revoke\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:delete\"\n ],\n \"unused_scopes\": [\n \"repo.delete:github/LubuSeb/sourcey-demo/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"No successful observed effect exercised this grant in the supplied run history.\",\n \"risk_notes\": [\n \"Revocation is safe only for the supplied evidence window; future workloads may require new authority.\"\n ]\n },\n {\n \"grant_id\": \"grant-secret-prod\",\n \"current_scope\": \"secret.read:prod/*\",\n \"recommendation\": \"needs_human_review\",\n \"proposed_scope\": null,\n \"observed_effects\": [\n {\n \"effect_id\": \"e-secret-denied\",\n \"verb\": \"secret.read\",\n \"resource\": \"prod/frantic-agent-token\",\n \"status\": \"denied\",\n \"receipt_ref\": \"runx:receipt:sha256:222#secret_denied\"\n }\n ],\n \"policy_input_refs\": [\n \"policy:secret-breakglass\"\n ],\n \"unused_scopes\": [\n \"secret.read:prod/*\"\n ],\n \"missing_evidence\": [\n \"Only a denied check exists; policy owner must decide whether this reserved secret scope is still required.\"\n ],\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#secret_denied\"\n ],\n \"rationale\": \"The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.\",\n \"risk_notes\": [\n \"Do not revoke or reduce this grant automatically until the missing evidence is resolved.\"\n ]\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"current_scope\": \"incident.breakglass:runx/*\",\n \"recommendation\": \"keep\",\n \"proposed_scope\": null,\n \"observed_effects\": [],\n \"policy_input_refs\": [\n \"policy:reserved\"\n ],\n \"unused_scopes\": [\n \"incident.breakglass:runx/*\"\n ],\n \"missing_evidence\": [],\n \"evidence_refs\": [],\n \"rationale\": \"The declared policy marks this grant as reserved or break-glass authority.\",\n \"risk_notes\": [\n \"Reserved grants remain broad by policy; schedule a separate human review if that posture changes.\"\n ]\n }\n ],\n \"evidence_json\": {\n \"schema\": \"frantic.delivery.evidence.v1\",\n \"artifact\": \"least-privilege-plan\",\n \"observations\": {\n \"policy_id\": \"runx-policy-demo-v1\",\n \"policy_digest\": \"sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9\",\n \"run_history_digest\": \"sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965\",\n \"subject\": \"skills/sourcey-docs\",\n \"grant_ids\": [\n \"grant-read-all\",\n \"grant-write-issues\",\n \"grant-delete\",\n \"grant-secret-prod\",\n \"grant-breakglass\"\n ],\n \"observed_effects\": [\n {\n \"effect_id\": \"e-read-issue\",\n \"grant_id\": \"grant-read-all\",\n \"verb\": \"repo.read\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:111#read_issue\"\n },\n {\n \"effect_id\": \"e-write-comment\",\n \"grant_id\": \"grant-write-issues\",\n \"verb\": \"repo.write\",\n \"resource\": \"github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"status\": \"success\",\n \"receipt_ref\": \"runx:receipt:sha256:222#comment\"\n },\n {\n \"effect_id\": \"e-secret-denied\",\n \"grant_id\": \"grant-secret-prod\",\n \"verb\": \"secret.read\",\n \"resource\": \"prod/frantic-agent-token\",\n \"status\": \"denied\",\n \"receipt_ref\": \"runx:receipt:sha256:222#secret_denied\"\n }\n ],\n \"unused_scopes\": [\n {\n \"grant_id\": \"grant-delete\",\n \"scope\": \"repo.delete:github/LubuSeb/sourcey-demo/*\"\n }\n ],\n \"recommendations\": [\n {\n \"grant_id\": \"grant-read-all\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.read:github/LubuSeb/sourcey-demo/issues/81\",\n \"evidence_refs\": [\n \"runx:receipt:sha256:111#read_issue\"\n ]\n },\n {\n \"grant_id\": \"grant-write-issues\",\n \"recommendation\": \"reduce\",\n \"proposed_scope\": \"repo.write:github/LubuSeb/sourcey-demo/issues/81/comments\",\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#comment\"\n ]\n },\n {\n \"grant_id\": \"grant-delete\",\n \"recommendation\": \"revoke\",\n \"proposed_scope\": null,\n \"evidence_refs\": []\n },\n {\n \"grant_id\": \"grant-secret-prod\",\n \"recommendation\": \"needs_human_review\",\n \"proposed_scope\": null,\n \"evidence_refs\": [\n \"runx:receipt:sha256:222#secret_denied\"\n ]\n },\n {\n \"grant_id\": \"grant-breakglass\",\n \"recommendation\": \"keep\",\n \"proposed_scope\": null,\n \"evidence_refs\": []\n }\n ],\n \"receipt_refs\": [\n \"runx:receipt:sha256:111\",\n \"runx:receipt:sha256:222\"\n ]\n }\n },\n \"report\": \"# least-privilege-plan report\\n\\nSubject: skills/sourcey-docs\\nPolicy: runx-policy-demo-v1\\nStatus: needs_human_review\\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\\n\\n## Recommendations\\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\\n\\nRead-only: true; mutates grants: false.\"\n}\n", + "structured_output": { + "evidence_json": { + "artifact": "least-privilege-plan", + "observations": { + "grant_ids": [ + "grant-read-all", + "grant-write-issues", + "grant-delete", + "grant-secret-prod", + "grant-breakglass" + ], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "grant_id": "grant-read-all", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + }, + { + "effect_id": "e-write-comment", + "grant_id": "grant-write-issues", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + }, + { + "effect_id": "e-secret-denied", + "grant_id": "grant-secret-prod", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_digest": "sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9", + "policy_id": "runx-policy-demo-v1", + "receipt_refs": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "recommendations": [ + { + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "recommendation": "reduce" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "recommendation": "reduce" + }, + { + "evidence_refs": [], + "grant_id": "grant-delete", + "proposed_scope": null, + "recommendation": "revoke" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "proposed_scope": null, + "recommendation": "needs_human_review" + }, + { + "evidence_refs": [], + "grant_id": "grant-breakglass", + "proposed_scope": null, + "recommendation": "keep" + } + ], + "run_history_digest": "sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965", + "subject": "skills/sourcey-docs", + "unused_scopes": [ + { + "grant_id": "grant-delete", + "scope": "repo.delete:github/LubuSeb/sourcey-demo/*" + } + ] + }, + "schema": "frantic.delivery.evidence.v1" + }, + "plan": { + "objective": "Hosted dogfood least privilege plan for Frantic bounty 37.", + "policy_id": "runx-policy-demo-v1", + "proposed_grants": [ + { + "grant_id": "grant-read-all", + "scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "source": "reduce" + }, + { + "grant_id": "grant-write-issues", + "scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "source": "reduce" + }, + { + "grant_id": "grant-breakglass", + "scope": "incident.breakglass:runx/*", + "source": "keep" + } + ], + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "safeguards": { + "mutates_grants": false, + "network_required": false, + "read_only": true, + "secrets_required": false + }, + "schema": "runx.security.least_privilege_plan.v1", + "source_receipts": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "status": "needs_human_review", + "subject": "skills/sourcey-docs", + "summary": { + "grant_count": 5, + "observed_effect_count": 3, + "recommendation_counts": { + "keep": 1, + "needs_human_review": 1, + "reduce": 2, + "revoke": 1 + } + } + }, + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "report": "# least-privilege-plan report\n\nSubject: skills/sourcey-docs\nPolicy: runx-policy-demo-v1\nStatus: needs_human_review\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\n\n## Recommendations\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\n\nRead-only: true; mutates grants: false." + } + }, + "payload": { + "evidence_json": { + "artifact": "least-privilege-plan", + "observations": { + "grant_ids": [ + "grant-read-all", + "grant-write-issues", + "grant-delete", + "grant-secret-prod", + "grant-breakglass" + ], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "grant_id": "grant-read-all", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + }, + { + "effect_id": "e-write-comment", + "grant_id": "grant-write-issues", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + }, + { + "effect_id": "e-secret-denied", + "grant_id": "grant-secret-prod", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_digest": "sha256:f9de1472ae8508bc4c5d5989263eaee7b7a5b749fb769089eedd6436f0f5adf9", + "policy_id": "runx-policy-demo-v1", + "receipt_refs": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "recommendations": [ + { + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "recommendation": "reduce" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "recommendation": "reduce" + }, + { + "evidence_refs": [], + "grant_id": "grant-delete", + "proposed_scope": null, + "recommendation": "revoke" + }, + { + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "proposed_scope": null, + "recommendation": "needs_human_review" + }, + { + "evidence_refs": [], + "grant_id": "grant-breakglass", + "proposed_scope": null, + "recommendation": "keep" + } + ], + "run_history_digest": "sha256:7aa9061a8fcb3de014fc3d813dffaae8ccf7eada3faa207932124e173f62a965", + "subject": "skills/sourcey-docs", + "unused_scopes": [ + { + "grant_id": "grant-delete", + "scope": "repo.delete:github/LubuSeb/sourcey-demo/*" + } + ] + }, + "schema": "frantic.delivery.evidence.v1" + }, + "plan": { + "objective": "Hosted dogfood least privilege plan for Frantic bounty 37.", + "policy_id": "runx-policy-demo-v1", + "proposed_grants": [ + { + "grant_id": "grant-read-all", + "scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "source": "reduce" + }, + { + "grant_id": "grant-write-issues", + "scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "source": "reduce" + }, + { + "grant_id": "grant-breakglass", + "scope": "incident.breakglass:runx/*", + "source": "keep" + } + ], + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "safeguards": { + "mutates_grants": false, + "network_required": false, + "read_only": true, + "secrets_required": false + }, + "schema": "runx.security.least_privilege_plan.v1", + "source_receipts": [ + "runx:receipt:sha256:111", + "runx:receipt:sha256:222" + ], + "status": "needs_human_review", + "subject": "skills/sourcey-docs", + "summary": { + "grant_count": 5, + "observed_effect_count": 3, + "recommendation_counts": { + "keep": 1, + "needs_human_review": 1, + "reduce": 2, + "revoke": 1 + } + } + }, + "recommendations": [ + { + "current_scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [ + "runx:receipt:sha256:111#read_issue" + ], + "grant_id": "grant-read-all", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "receipt_ref": "runx:receipt:sha256:111#read_issue", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "verb": "repo.read" + } + ], + "policy_input_refs": [ + "policy:repo-read" + ], + "proposed_scope": "repo.read:github/LubuSeb/sourcey-demo/issues/81", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.read:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "evidence_refs": [ + "runx:receipt:sha256:222#comment" + ], + "grant_id": "grant-write-issues", + "missing_evidence": [], + "observed_effects": [ + { + "effect_id": "e-write-comment", + "receipt_ref": "runx:receipt:sha256:222#comment", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "verb": "repo.write" + } + ], + "policy_input_refs": [ + "policy:issue-write" + ], + "proposed_scope": "repo.write:github/LubuSeb/sourcey-demo/issues/81/comments", + "rationale": "Successful observed effects fit a narrower resource path than the current wildcard grant.", + "recommendation": "reduce", + "risk_notes": [ + "The reduced scope preserves only the cited resources from this evidence packet." + ], + "unused_scopes": [ + "repo.write:github/LubuSeb/sourcey-demo/issues/*" + ] + }, + { + "current_scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "evidence_refs": [], + "grant_id": "grant-delete", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:delete" + ], + "proposed_scope": null, + "rationale": "No successful observed effect exercised this grant in the supplied run history.", + "recommendation": "revoke", + "risk_notes": [ + "Revocation is safe only for the supplied evidence window; future workloads may require new authority." + ], + "unused_scopes": [ + "repo.delete:github/LubuSeb/sourcey-demo/*" + ] + }, + { + "current_scope": "secret.read:prod/*", + "evidence_refs": [ + "runx:receipt:sha256:222#secret_denied" + ], + "grant_id": "grant-secret-prod", + "missing_evidence": [ + "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + ], + "observed_effects": [ + { + "effect_id": "e-secret-denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied", + "resource": "prod/frantic-agent-token", + "status": "denied", + "verb": "secret.read" + } + ], + "policy_input_refs": [ + "policy:secret-breakglass" + ], + "proposed_scope": null, + "rationale": "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + "recommendation": "needs_human_review", + "risk_notes": [ + "Do not revoke or reduce this grant automatically until the missing evidence is resolved." + ], + "unused_scopes": [ + "secret.read:prod/*" + ] + }, + { + "current_scope": "incident.breakglass:runx/*", + "evidence_refs": [], + "grant_id": "grant-breakglass", + "missing_evidence": [], + "observed_effects": [], + "policy_input_refs": [ + "policy:reserved" + ], + "proposed_scope": null, + "rationale": "The declared policy marks this grant as reserved or break-glass authority.", + "recommendation": "keep", + "risk_notes": [ + "Reserved grants remain broad by policy; schedule a separate human review if that posture changes." + ], + "unused_scopes": [ + "incident.breakglass:runx/*" + ] + } + ], + "report": "# least-privilege-plan report\n\nSubject: skills/sourcey-docs\nPolicy: runx-policy-demo-v1\nStatus: needs_human_review\nReceipts: runx:receipt:sha256:111, runx:receipt:sha256:222\n\n## Recommendations\n- reduce: grant-read-all repo.read:github/LubuSeb/sourcey-demo/* -> repo.read:github/LubuSeb/sourcey-demo/issues/81 (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- reduce: grant-write-issues repo.write:github/LubuSeb/sourcey-demo/issues/* -> repo.write:github/LubuSeb/sourcey-demo/issues/81/comments (Successful observed effects fit a narrower resource path than the current wildcard grant.)\n- revoke: grant-delete repo.delete:github/LubuSeb/sourcey-demo/* (No successful observed effect exercised this grant in the supplied run history.)\n- needs_human_review: grant-secret-prod secret.read:prod/* (The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.)\n- keep: grant-breakglass incident.breakglass:runx/* (The declared policy marks this grant as reserved or break-glass authority.)\n\nRead-only: true; mutates grants: false." + }, + "receipt": { + "acts": [ + { + "artifact_refs": [], + "closure": { + "closed_at": "2026-06-22T14:38:42.900Z", + "disposition": "closed", + "reason_code": "process_exit", + "summary": "cli-tool exited successfully" + }, + "criterion_bindings": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "form": "observation", + "id": "act_default", + "intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Runtime graph execution was admitted by the local harness", + "purpose": "Run graph step default", + "success_criteria": [ + { + "criterion_id": "process_exit", + "required": true, + "statement": "cli-tool exits successfully" + } + ] + }, + "source_refs": [], + "summary": "Executed graph step default", + "target_refs": [] + } + ], + "authority": { + "actor_ref": { + "type": "principal", + "uri": "runx:principal:local_runtime" + }, + "attenuation": { + "parent_authority_ref": null, + "subset_proof": null + }, + "authority_proof_refs": [], + "enforcement": { + "profile_hash": "sha256:runtime-skeleton-enforcement", + "redaction_refs": [], + "setup_refs": [], + "teardown_refs": [] + }, + "grant_refs": [], + "scope_refs": [], + "terms": [] + }, + "canonicalization": "runx.receipt.c14n.v1", + "created_at": "2026-06-22T14:38:42.900Z", + "decisions": [ + { + "artifact_refs": [], + "choice": "open", + "closure": null, + "decision_id": "dec_default", + "inputs": { + "opportunity_refs": [], + "selection_ref": null, + "signal_refs": [], + "target_ref": null + }, + "justification": { + "evidence_refs": [], + "summary": "runtime graph planner selected this node" + }, + "proposed_intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Local graph execution requested this node", + "purpose": "Open runtime node default", + "success_criteria": [] + }, + "selected_act_id": "act_default", + "selected_harness_ref": null + } + ], + "digest": "sha256:50484eb4284019f8a3050efedd4ff8d07c9b09f82c503e67a404bd8758a1b541", + "id": "sha256:434a5446b2f7d85b35a2ff9ec70ba48d25c8bf06b8cb64f0f79ff4a576f33d77", + "idempotency": { + "content_hash": "sha256:run_default_799e8544dbfd-default-content", + "intent_key": "sha256:run_default_799e8544dbfd-default-intent", + "trigger_fingerprint": "sha256:run_default_799e8544dbfd-default-trigger" + }, + "issuer": { + "kid": "local:bountybar-frantic-runx-22-20260618192655", + "public_key_sha256": "sha256:afae74faf1b1b104b27d788bee2dd0982052af89a1ae30b3282f1a14b0707871", + "type": "hosted" + }, + "lineage": { + "children": [], + "sync": [] + }, + "schema": "runx.receipt.v1", + "seal": { + "closed_at": "2026-06-22T14:38:42.900Z", + "criteria": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "disposition": "closed", + "last_observed_at": "2026-06-22T14:38:42.900Z", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "signals": [], + "signature": { + "alg": "Ed25519", + "value": "base64:beTqJciXTFi0qnMl6g8rPCLpImEpTSUJTcNoqNBYH7e8klQF1i1MmBdSSNkfxBdd6KEZjXb3IbR3bG3N-YQwDQ" + }, + "subject": { + "commitments": [], + "kind": "skill", + "ref": { + "type": "harness", + "uri": "hrn_run_default_799e8544dbfd_default" + } + } + }, + "receipt_id": "sha256:434a5446b2f7d85b35a2ff9ec70ba48d25c8bf06b8cb64f0f79ff4a576f33d77", + "registry_provenance": { + "digest": "sha256:09c761cf110265d8e5ddc4453fb4cff90cd5b775920557cd4eda384ae20af471", + "profile_digest": "sha256:259c08c1e5725838b9cd593e7a595c883ad10a4ed8d8b2107bfb3cd712977d4e", + "registry_key_id": "runx-registry-ed25519-v1", + "registry_source": "remote https://api.runx.ai", + "registry_source_fingerprint": "ba1ac16b631195fd", + "skill_id": "lubuseb/least-privilege-plan", + "trust_state": "trusted", + "trust_tier": "community", + "version": "sha-2ed0e113ff52" + }, + "run_id": "run_default_799e8544dbfd", + "schema": "runx.skill_run.v1", + "skill_name": "least-privilege-plan", + "status": "sealed" +} diff --git a/skills/least-privilege-plan/evidence/hosted-dogfood-receipts-linux.tgz b/skills/least-privilege-plan/evidence/hosted-dogfood-receipts-linux.tgz new file mode 100644 index 00000000..3d3f29a3 Binary files /dev/null and b/skills/least-privilege-plan/evidence/hosted-dogfood-receipts-linux.tgz differ diff --git a/skills/least-privilege-plan/evidence/hosted-harness-receipts-linux.tgz b/skills/least-privilege-plan/evidence/hosted-harness-receipts-linux.tgz new file mode 100644 index 00000000..b196988c Binary files /dev/null and b/skills/least-privilege-plan/evidence/hosted-harness-receipts-linux.tgz differ diff --git a/skills/least-privilege-plan/evidence/hosted-harness-verification.json b/skills/least-privilege-plan/evidence/hosted-harness-verification.json new file mode 100644 index 00000000..f3c2cc1d --- /dev/null +++ b/skills/least-privilege-plan/evidence/hosted-harness-verification.json @@ -0,0 +1,43 @@ +{ + "receipt_dir": "/tmp/runx-least-privilege-plan-hosted-harness-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:17bc1ca8f4fb32bba7d63eb5683bcb34991b04d892fbb8a8514191b3a5444ae5", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:881ab39da888bef5a16f4e2623026d16740ad8ed3a25794c569c1b0aa7f383fb", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:9c94830528f600bcc5055cc34d76bb55af2821be56a9f6bacdfd2e6aa97ef75d", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:bafd311064f865420eb0ee9635e8494356c6ed5d3c7ce719a6e6de9c5ad72c12", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:be03ce38ccef39f28a4588215a03fae4eb077e01972ad5514bc9f33a6f014d61", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/least-privilege-plan/evidence/hosted-harness.json b/skills/least-privilege-plan/evidence/hosted-harness.json new file mode 100644 index 00000000..e48afeda --- /dev/null +++ b/skills/least-privilege-plan/evidence/hosted-harness.json @@ -0,0 +1,21 @@ +{ + "status": "passed", + "case_count": 5, + "assertion_error_count": 0, + "assertion_errors": [], + "case_names": [ + "over-broad-grant-plan", + "justified-grant-plan", + "missing-grants-fails-closed", + "invalid-effect-status-fails-closed", + "policy-mismatch-fails-closed" + ], + "receipt_ids": [ + "sha256:881ab39da888bef5a16f4e2623026d16740ad8ed3a25794c569c1b0aa7f383fb", + "sha256:17bc1ca8f4fb32bba7d63eb5683bcb34991b04d892fbb8a8514191b3a5444ae5", + "sha256:9c94830528f600bcc5055cc34d76bb55af2821be56a9f6bacdfd2e6aa97ef75d", + "sha256:bafd311064f865420eb0ee9635e8494356c6ed5d3c7ce719a6e6de9c5ad72c12", + "sha256:be03ce38ccef39f28a4588215a03fae4eb077e01972ad5514bc9f33a6f014d61" + ], + "graph_case_count": 0 +} diff --git a/skills/least-privilege-plan/evidence/hosted-verification.json b/skills/least-privilege-plan/evidence/hosted-verification.json new file mode 100644 index 00000000..890bb5bd --- /dev/null +++ b/skills/least-privilege-plan/evidence/hosted-verification.json @@ -0,0 +1,15 @@ +{ + "receipt_dir": "/tmp/runx-least-privilege-plan-hosted-dogfood-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:434a5446b2f7d85b35a2ff9ec70ba48d25c8bf06b8cb64f0f79ff4a576f33d77", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/least-privilege-plan/evidence/local-harness-receipts-linux.tgz b/skills/least-privilege-plan/evidence/local-harness-receipts-linux.tgz new file mode 100644 index 00000000..3dcfbef2 Binary files /dev/null and b/skills/least-privilege-plan/evidence/local-harness-receipts-linux.tgz differ diff --git a/skills/least-privilege-plan/evidence/local-harness-verification.json b/skills/least-privilege-plan/evidence/local-harness-verification.json new file mode 100644 index 00000000..ad7b47f4 --- /dev/null +++ b/skills/least-privilege-plan/evidence/local-harness-verification.json @@ -0,0 +1,43 @@ +{ + "receipt_dir": "/tmp/runx-least-privilege-plan-harness-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:1b26af95abe63a45f0435dd94f456ccd91cd79b3722e82eb0f12b68f19d356f6", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:528dc0578170ed9e84d02594681d3b32ff5507126251724002ccb00895f91fdc", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:9986f6adc387c0ecdd3e80636dcdfb17d31c854392603a0f792bc38708ac5f56", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:d3b898bef617c61bda97f989dd774a6213958974f55e3ffaec14708906d2d25b", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:f9ccd81249919052b7289653fdd890577f580a63d2bc9fc7bb6d07ec70bd30b6", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/least-privilege-plan/evidence/local-harness.json b/skills/least-privilege-plan/evidence/local-harness.json new file mode 100644 index 00000000..0485f0ee --- /dev/null +++ b/skills/least-privilege-plan/evidence/local-harness.json @@ -0,0 +1,21 @@ +{ + "status": "passed", + "case_count": 5, + "assertion_error_count": 0, + "assertion_errors": [], + "case_names": [ + "over-broad-grant-plan", + "justified-grant-plan", + "missing-grants-fails-closed", + "invalid-effect-status-fails-closed", + "policy-mismatch-fails-closed" + ], + "receipt_ids": [ + "sha256:528dc0578170ed9e84d02594681d3b32ff5507126251724002ccb00895f91fdc", + "sha256:1b26af95abe63a45f0435dd94f456ccd91cd79b3722e82eb0f12b68f19d356f6", + "sha256:d3b898bef617c61bda97f989dd774a6213958974f55e3ffaec14708906d2d25b", + "sha256:f9ccd81249919052b7289653fdd890577f580a63d2bc9fc7bb6d07ec70bd30b6", + "sha256:9986f6adc387c0ecdd3e80636dcdfb17d31c854392603a0f792bc38708ac5f56" + ], + "graph_case_count": 0 +} diff --git a/skills/least-privilege-plan/evidence/registry-publish.json b/skills/least-privilege-plan/evidence/registry-publish.json new file mode 100644 index 00000000..cdb73598 --- /dev/null +++ b/skills/least-privilege-plan/evidence/registry-publish.json @@ -0,0 +1,20 @@ +{ + "status": "success", + "registry": { + "action": "publish", + "publish": { + "target": "hosted", + "status": "published", + "skill_id": "lubuseb/least-privilege-plan", + "owner": "lubuseb", + "name": "least-privilege-plan", + "version": "sha-2ed0e113ff52", + "digest": "09c761cf110265d8e5ddc4453fb4cff90cd5b775920557cd4eda384ae20af471", + "profile_digest": "259c08c1e5725838b9cd593e7a595c883ad10a4ed8d8b2107bfb3cd712977d4e", + "trust_tier": "community", + "install_command": "runx add lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai", + "run_command": "runx skill lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai", + "public_url": "https://runx.ai/x/lubuseb/least-privilege-plan" + } + } +} diff --git a/skills/least-privilege-plan/evidence/registry-read.json b/skills/least-privilege-plan/evidence/registry-read.json new file mode 100644 index 00000000..7b6fa565 --- /dev/null +++ b/skills/least-privilege-plan/evidence/registry-read.json @@ -0,0 +1,50 @@ +{ + "status": "success", + "registry": { + "action": "read", + "source": "remote", + "ref": "lubuseb/least-privilege-plan@sha-2ed0e113ff52", + "skill": { + "skill_id": "lubuseb/least-privilege-plan", + "owner": "lubuseb", + "name": "least-privilege-plan", + "description": "Produce a read-only least-privilege grant plan from bounded run history and a declared policy.", + "category": "security", + "version": "sha-2ed0e113ff52", + "digest": "09c761cf110265d8e5ddc4453fb4cff90cd5b775920557cd4eda384ae20af471", + "markdown": "---\nname: least-privilege-plan\ndescription: Produce a read-only least-privilege grant plan from bounded run history and a declared policy.\nsource:\n type: cli-tool\n command: node\n args:\n - run.mjs\n input_mode: stdin\n cwd: .\n timeout_seconds: 30\ninputs:\n run_history_packet:\n type: json\n required: true\n description: Bounded run history containing grants, observed effects, receipt refs, and missing-evidence notes.\n policy:\n type: json\n required: true\n description: Declared least-privilege policy with grant metadata, reserved scopes, and review rules.\n objective:\n type: string\n required: false\n description: Optional operator intent for the plan.\nrunx:\n category: security\n input_resolution:\n required:\n - run_history_packet\n - policy\n---\n\n# least-privilege-plan\n\nUse this skill when an operator needs a read-only plan for narrowing granted\nauthority after one or more runs. The skill compares a bounded run history\npacket against a declared policy and emits keep, reduce, revoke, and\nneeds_human_review recommendations with cited evidence.\n\nThe skill does not mutate grants, write credentials, call provider APIs, or infer\nauthority from broad task success. Every recommendation cites exact observed\neffects, policy inputs, unused scopes, or missing evidence so a reviewer can\napply the plan separately.\n\n## Inputs\n\n- `run_history_packet`: bounded JSON with `subject`, `policy_id`, `grants`,\n `observed_effects`, `receipt_refs`, and optional `missing_evidence`.\n- `policy`: declared JSON policy with grant metadata, reserved scopes, wildcard\n rules, and review thresholds.\n- `objective`: optional operator intent.\n\n## Output\n\nThe runner returns JSON with:\n\n- `plan`: the typed least-privilege plan.\n- `recommendations`: one recommendation per grant.\n- `evidence_json`: a compact evidence object suitable for external review.\n- `report`: a human-readable summary.\n\nRecommendation actions are exactly `keep`, `reduce`, `revoke`, and\n`needs_human_review`.", + "profile_digest": "259c08c1e5725838b9cd593e7a595c883ad10a4ed8d8b2107bfb3cd712977d4e", + "runner_names": [ + "default" + ], + "source_type": "cli-tool", + "trust_tier": "community", + "required_scopes": [], + "tags": [], + "publisher": { + "kind": "user", + "id": "user_53f00ae7ec2363e37ac6ff68", + "handle": "lubuseb", + "display_name": "LubuSeb" + }, + "attestations": [ + { + "kind": "publisher", + "id": "publisher:user_53f00ae7ec2363e37ac6ff68", + "status": "declared", + "summary": "LubuSeb", + "issued_at": "2026-06-22T14:38:27.637Z", + "metadata": { + "publisher_display_name": "LubuSeb", + "publisher_handle": "lubuseb", + "publisher_id": "user_53f00ae7ec2363e37ac6ff68", + "publisher_kind": "user", + "trust_tier": "community" + } + } + ], + "install_command": "runx add lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai", + "run_command": "runx skill lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai" + } + } +} diff --git a/skills/least-privilege-plan/evidence/report.md b/skills/least-privilege-plan/evidence/report.md new file mode 100644 index 00000000..c1773ca7 --- /dev/null +++ b/skills/least-privilege-plan/evidence/report.md @@ -0,0 +1,23 @@ +# least-privilege-plan delivery report + +- Package: `lubuseb/least-privilege-plan@sha-2ed0e113ff52`. +- Public registry URL: `https://runx.ai/x/lubuseb/least-privilege-plan@sha-2ed0e113ff52`. +- Source PR: `https://github.com/runxhq/runx/pull/118`. +- `runx-cli 0.6.13` was used for publish, registry read, clean install, harness, dogfood, and receipt verification. +- Local harness passed five cases: `over-broad-grant-plan`, `justified-grant-plan`, `missing-grants-fails-closed`, `invalid-effect-status-fails-closed`, and `policy-mismatch-fails-closed`. +- Hosted clean install succeeded with `runx add lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai`. +- Harness from the clean installed package passed the same five cases and all harness receipts verified. +- Hosted dogfood produced sealed receipt `runx:receipt:sha256:434a5446b2f7d85b35a2ff9ec70ba48d25c8bf06b8cb64f0f79ff4a576f33d77`. +- `runx verify` returned `valid=true` and no findings for the dogfood receipt. +- The runner emits `keep`, `reduce`, `revoke`, and `needs_human_review` recommendations with exact observed effects, policy refs, unused scopes, or missing evidence. +- The implementation is read-only: it reads the provided JSON packet and policy, computes recommendations in memory, requires no credentials, performs no network/provider calls, and emits structured stdout. + +Reproduce: + +```bash +runx add lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai +runx registry read lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai --json +runx harness ./least-privilege-plan --json +runx skill lubuseb/least-privilege-plan@sha-2ed0e113ff52 --registry https://api.runx.ai --input-json run_history_packet='' --input-json policy='' --json +runx verify --receipt-dir /tmp/runx-least-privilege-plan-hosted-dogfood-receipts --json +``` diff --git a/skills/least-privilege-plan/evidence/runx-version.txt b/skills/least-privilege-plan/evidence/runx-version.txt new file mode 100644 index 00000000..6ff8172c --- /dev/null +++ b/skills/least-privilege-plan/evidence/runx-version.txt @@ -0,0 +1 @@ +runx-cli 0.6.13 diff --git a/skills/least-privilege-plan/evidence/verification.json b/skills/least-privilege-plan/evidence/verification.json new file mode 100644 index 00000000..3ec6dd90 --- /dev/null +++ b/skills/least-privilege-plan/evidence/verification.json @@ -0,0 +1,15 @@ +{ + "receipt_dir": "/tmp/runx-least-privilege-plan-dogfood-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:cfceaadb4aee0c212b40c4eb2a554f5df3a6e5fbf0ea0df7538efc627e839a15", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/least-privilege-plan/fixtures/over-broad-run-history.json b/skills/least-privilege-plan/fixtures/over-broad-run-history.json new file mode 100644 index 00000000..02075352 --- /dev/null +++ b/skills/least-privilege-plan/fixtures/over-broad-run-history.json @@ -0,0 +1,64 @@ +{ + "subject": "skills/sourcey-docs", + "policy_id": "runx-policy-demo-v1", + "receipt_refs": ["runx:receipt:sha256:111", "runx:receipt:sha256:222"], + "grants": [ + { + "grant_id": "grant-read-all", + "scope": "repo.read:github/LubuSeb/sourcey-demo/*", + "declared_policy_ref": "policy:repo-read" + }, + { + "grant_id": "grant-write-issues", + "scope": "repo.write:github/LubuSeb/sourcey-demo/issues/*", + "declared_policy_ref": "policy:issue-write" + }, + { + "grant_id": "grant-delete", + "scope": "repo.delete:github/LubuSeb/sourcey-demo/*", + "declared_policy_ref": "policy:delete" + }, + { + "grant_id": "grant-secret-prod", + "scope": "secret.read:prod/*", + "declared_policy_ref": "policy:secret-breakglass" + }, + { + "grant_id": "grant-breakglass", + "scope": "incident.breakglass:runx/*", + "declared_policy_ref": "policy:reserved" + } + ], + "observed_effects": [ + { + "effect_id": "e-read-issue", + "grant_id": "grant-read-all", + "verb": "repo.read", + "resource": "github/LubuSeb/sourcey-demo/issues/81", + "status": "success", + "receipt_ref": "runx:receipt:sha256:111#read_issue" + }, + { + "effect_id": "e-write-comment", + "grant_id": "grant-write-issues", + "verb": "repo.write", + "resource": "github/LubuSeb/sourcey-demo/issues/81/comments", + "status": "success", + "receipt_ref": "runx:receipt:sha256:222#comment" + }, + { + "effect_id": "e-secret-denied", + "grant_id": "grant-secret-prod", + "verb": "secret.read", + "resource": "prod/frantic-agent-token", + "status": "denied", + "receipt_ref": "runx:receipt:sha256:222#secret_denied" + } + ], + "missing_evidence": [ + { + "grant_id": "grant-secret-prod", + "reason": "Only a denied check exists; policy owner must decide whether this reserved secret scope is still required." + } + ] +} diff --git a/skills/least-privilege-plan/fixtures/policy.json b/skills/least-privilege-plan/fixtures/policy.json new file mode 100644 index 00000000..4df7bd2d --- /dev/null +++ b/skills/least-privilege-plan/fixtures/policy.json @@ -0,0 +1,8 @@ +{ + "policy_id": "runx-policy-demo-v1", + "review_rules": { + "wildcard_reduction_allowed": true, + "require_human_review_for_denied_secret": true + }, + "reserved_grants": ["grant-breakglass"] +} diff --git a/skills/least-privilege-plan/run.mjs b/skills/least-privilege-plan/run.mjs new file mode 100644 index 00000000..11cb87d0 --- /dev/null +++ b/skills/least-privilege-plan/run.mjs @@ -0,0 +1,342 @@ +import fs from "node:fs"; +import crypto from "node:crypto"; + +const inputs = readInputs(); +const history = requireObject(inputs.run_history_packet, "run_history_packet"); +const policy = requireObject(inputs.policy, "policy"); +const objective = stringValue(inputs.objective) || "Produce a least-privilege grant plan."; + +const subject = stringValue(history.subject) || "unknown-subject"; +const historyPolicyId = stringValue(history.policy_id); +const declaredPolicyId = stringValue(policy.policy_id); +if (!historyPolicyId) throw new Error("run_history_packet.policy_id is required"); +if (!declaredPolicyId) throw new Error("policy.policy_id is required"); +if (historyPolicyId !== declaredPolicyId) { + throw new Error("run_history_packet.policy_id must match policy.policy_id"); +} +const policyId = declaredPolicyId; +const grants = normalizeGrants(history.grants); +const effects = normalizeEffects(history.observed_effects); +const missingEvidence = normalizeMissingEvidence(history.missing_evidence); +const reservedGrantIds = new Set(arrayValue(policy.reserved_grants).map(String)); +const reviewRules = isObject(policy.review_rules) ? policy.review_rules : {}; + +const recommendations = grants.map((grant) => + recommendGrant(grant, effects, missingEvidence, reservedGrantIds, reviewRules), +); + +const counts = recommendations.reduce( + (acc, rec) => { + acc[rec.recommendation] = (acc[rec.recommendation] || 0) + 1; + return acc; + }, + { keep: 0, reduce: 0, revoke: 0, needs_human_review: 0 }, +); + +const status = + counts.needs_human_review > 0 + ? "needs_human_review" + : counts.reduce > 0 || counts.revoke > 0 + ? "attenuation_proposed" + : "no_change"; + +const plan = { + schema: "runx.security.least_privilege_plan.v1", + status, + subject, + objective, + policy_id: policyId, + source_receipts: arrayValue(history.receipt_refs).map(String), + recommendations, + proposed_grants: recommendations + .filter((rec) => rec.recommendation === "keep" || rec.recommendation === "reduce") + .map((rec) => ({ + grant_id: rec.grant_id, + scope: rec.proposed_scope || rec.current_scope, + source: rec.recommendation, + })), + summary: { + grant_count: grants.length, + observed_effect_count: effects.length, + recommendation_counts: counts, + }, + safeguards: { + read_only: true, + mutates_grants: false, + network_required: false, + secrets_required: false, + }, +}; + +const evidenceJson = { + schema: "frantic.delivery.evidence.v1", + artifact: "least-privilege-plan", + observations: { + policy_id: policyId, + policy_digest: sha256Json(policy), + run_history_digest: sha256Json(history), + subject, + grant_ids: grants.map((grant) => grant.grant_id), + observed_effects: effects.map((effect) => ({ + effect_id: effect.effect_id, + grant_id: effect.grant_id, + verb: effect.verb, + resource: effect.resource, + status: effect.status, + receipt_ref: effect.receipt_ref, + })), + unused_scopes: recommendations + .filter((rec) => rec.recommendation === "revoke") + .map((rec) => ({ grant_id: rec.grant_id, scope: rec.current_scope })), + recommendations: recommendations.map((rec) => ({ + grant_id: rec.grant_id, + recommendation: rec.recommendation, + proposed_scope: rec.proposed_scope, + evidence_refs: rec.evidence_refs, + })), + receipt_refs: plan.source_receipts, + }, +}; + +const report = renderReport(plan); + +process.stdout.write(`${JSON.stringify({ plan, recommendations, evidence_json: evidenceJson, report }, null, 2)}\n`); + +function recommendGrant(grant, effects, missingEvidence, reservedGrantIds, reviewRules) { + const grantEffects = effects.filter((effect) => effect.grant_id === grant.grant_id); + const successEffects = grantEffects.filter((effect) => effect.status === "success"); + const deniedEffects = grantEffects.filter((effect) => effect.status === "denied"); + const missing = missingEvidence.filter((entry) => entry.grant_id === grant.grant_id); + const policyRefs = [grant.declared_policy_ref].filter(Boolean); + const evidenceRefs = grantEffects.map((effect) => effect.receipt_ref).filter(Boolean); + + if (missing.length > 0 || (deniedEffects.length > 0 && reviewRules.require_human_review_for_denied_secret)) { + return buildRecommendation({ + grant, + recommendation: "needs_human_review", + proposedScope: null, + observedEffects: grantEffects, + evidenceRefs, + policyRefs, + unusedScopes: successEffects.length === 0 ? [grant.scope] : [], + missingEvidence: missing.map((entry) => entry.reason), + rationale: + "The grant has missing or denied evidence that could change the attenuation decision; a policy owner must review it.", + riskNotes: ["Do not revoke or reduce this grant automatically until the missing evidence is resolved."], + }); + } + + if (reservedGrantIds.has(grant.grant_id)) { + return buildRecommendation({ + grant, + recommendation: "keep", + proposedScope: null, + observedEffects: grantEffects, + evidenceRefs, + policyRefs, + unusedScopes: successEffects.length === 0 ? [grant.scope] : [], + missingEvidence: [], + rationale: "The declared policy marks this grant as reserved or break-glass authority.", + riskNotes: ["Reserved grants remain broad by policy; schedule a separate human review if that posture changes."], + }); + } + + if (successEffects.length === 0) { + return buildRecommendation({ + grant, + recommendation: "revoke", + proposedScope: null, + observedEffects: grantEffects, + evidenceRefs, + policyRefs, + unusedScopes: [grant.scope], + missingEvidence: [], + rationale: "No successful observed effect exercised this grant in the supplied run history.", + riskNotes: ["Revocation is safe only for the supplied evidence window; future workloads may require new authority."], + }); + } + + const proposedScope = narrowerScope(grant.scope, successEffects); + if (proposedScope && proposedScope !== grant.scope && reviewRules.wildcard_reduction_allowed !== false) { + return buildRecommendation({ + grant, + recommendation: "reduce", + proposedScope, + observedEffects: successEffects, + evidenceRefs, + policyRefs, + unusedScopes: [grant.scope], + missingEvidence: [], + rationale: "Successful observed effects fit a narrower resource path than the current wildcard grant.", + riskNotes: ["The reduced scope preserves only the cited resources from this evidence packet."], + }); + } + + return buildRecommendation({ + grant, + recommendation: "keep", + proposedScope: null, + observedEffects: successEffects, + evidenceRefs, + policyRefs, + unusedScopes: [], + missingEvidence: [], + rationale: "Successful observed effects require the current grant as declared.", + riskNotes: [], + }); +} + +function buildRecommendation({ + grant, + recommendation, + proposedScope, + observedEffects, + evidenceRefs, + policyRefs, + unusedScopes, + missingEvidence, + rationale, + riskNotes, +}) { + return { + grant_id: grant.grant_id, + current_scope: grant.scope, + recommendation, + proposed_scope: proposedScope, + observed_effects: observedEffects.map((effect) => ({ + effect_id: effect.effect_id, + verb: effect.verb, + resource: effect.resource, + status: effect.status, + receipt_ref: effect.receipt_ref, + })), + policy_input_refs: policyRefs, + unused_scopes: unusedScopes, + missing_evidence: missingEvidence, + evidence_refs: evidenceRefs, + rationale, + risk_notes: riskNotes, + }; +} + +function narrowerScope(scope, successEffects) { + if (!scope.endsWith("*") || successEffects.length === 0) return null; + const [verbPrefix, resourcePrefix = ""] = scope.slice(0, -1).split(/:(.*)/s); + const resources = [...new Set(successEffects.map((effect) => effect.resource).filter(Boolean))]; + if (resources.length !== 1) return null; + const observedResource = resources[0]; + if (!observedResource.startsWith(resourcePrefix)) return null; + return `${verbPrefix}:${observedResource}`; +} + +function normalizeGrants(value) { + const grants = arrayValue(value).map((grant, index) => { + if (!isObject(grant)) throw new Error(`grants[${index}] must be an object`); + const grantId = stringValue(grant.grant_id) || `grant-${index + 1}`; + const scope = stringValue(grant.scope); + if (!scope) throw new Error(`grants[${index}].scope is required`); + return { + grant_id: grantId, + scope, + declared_policy_ref: stringValue(grant.declared_policy_ref), + }; + }); + if (grants.length === 0) throw new Error("run_history_packet.grants must contain at least one grant"); + return grants; +} + +function normalizeEffects(value) { + return arrayValue(value).map((effect, index) => { + if (!isObject(effect)) throw new Error(`observed_effects[${index}] must be an object`); + return { + effect_id: stringValue(effect.effect_id) || `effect-${index + 1}`, + grant_id: stringValue(effect.grant_id) || "", + verb: stringValue(effect.verb) || "", + resource: stringValue(effect.resource) || "", + status: normalizeStatus(effect.status, index), + receipt_ref: stringValue(effect.receipt_ref) || "", + }; + }); +} + +function normalizeMissingEvidence(value) { + return arrayValue(value).map((entry, index) => { + if (!isObject(entry)) throw new Error(`missing_evidence[${index}] must be an object`); + return { + grant_id: stringValue(entry.grant_id) || "", + reason: stringValue(entry.reason) || "missing evidence", + }; + }); +} + +function normalizeStatus(value, index) { + const normalized = stringValue(value); + if (!normalized) throw new Error(`observed_effects[${index}].status is required`); + if (["success", "denied", "dry_run"].includes(normalized)) return normalized; + throw new Error(`observed_effects[${index}].status must be success, denied, or dry_run`); +} + +function renderReport(plan) { + const lines = [ + `# least-privilege-plan report`, + ``, + `Subject: ${plan.subject}`, + `Policy: ${plan.policy_id}`, + `Status: ${plan.status}`, + `Receipts: ${plan.source_receipts.join(", ") || "none supplied"}`, + ``, + `## Recommendations`, + ...plan.recommendations.map( + (rec) => + `- ${rec.recommendation}: ${rec.grant_id} ${rec.current_scope}` + + (rec.proposed_scope ? ` -> ${rec.proposed_scope}` : "") + + ` (${rec.rationale})`, + ), + ``, + `Read-only: ${plan.safeguards.read_only}; mutates grants: ${plan.safeguards.mutates_grants}.`, + ]; + return lines.join("\n"); +} + +function readInputs() { + if (process.env.RUNX_INPUTS_PATH) { + return JSON.parse(fs.readFileSync(process.env.RUNX_INPUTS_PATH, "utf8")); + } + if (process.env.RUNX_INPUTS_JSON) { + return JSON.parse(process.env.RUNX_INPUTS_JSON); + } + if (!process.stdin.isTTY) { + const raw = fs.readFileSync(0, "utf8").trim(); + if (raw) return JSON.parse(raw); + } + return {}; +} + +function requireObject(value, field) { + if (!isObject(value)) throw new Error(`${field} must be an object`); + return value; +} + +function isObject(value) { + return Boolean(value) && typeof value === "object" && !Array.isArray(value); +} + +function arrayValue(value) { + return Array.isArray(value) ? value : []; +} + +function stringValue(value) { + return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; +} + +function sha256Json(value) { + return `sha256:${crypto.createHash("sha256").update(JSON.stringify(sortJson(value))).digest("hex")}`; +} + +function sortJson(value) { + if (Array.isArray(value)) return value.map(sortJson); + if (isObject(value)) { + return Object.fromEntries(Object.keys(value).sort().map((key) => [key, sortJson(value[key])])); + } + return value; +}