@raishin/vanguard-frontier-agentic 3.11.0 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/tasks/task-rust-tui-implementation/2025-01-15-120000-review.md +1 -1
- package/.agents/tasks/task-rust-tui-implementation/task.json +1 -1
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +7 -1
- package/.cursor-plugin/plugin.json +25 -1
- package/.github/plugin/marketplace.json +1 -1
- package/README.md +13 -13
- package/agents/AGENTS.md +24 -24
- package/agents/README.md +17 -17
- package/agents/ionos/ionos-cost-optimization-analyst-agent/metadata.json +17 -3
- package/agents/ionos/ionos-datacenter-designer-reviewer-agent/metadata.json +17 -3
- package/agents/ionos/ionos-kubernetes-platform-operator-agent/metadata.json +17 -3
- package/agents/ionos/ionos-live-database-lifecycle-guard-agent/metadata.json +17 -3
- package/agents/ionos/ionos-maestro-agent/metadata.json +17 -3
- package/agents/ionos/ionos-security-compliance-reviewer-agent/metadata.json +17 -3
- package/agents/istio/README.md +16 -8
- package/agents/istio/istio-ambient-mesh-review-agent/AGENT.md +19 -23
- package/agents/istio/istio-ambient-mesh-review-agent/harnesses/claude-code.agent.md +20 -20
- package/agents/istio/istio-ambient-mesh-review-agent/harnesses/codex.toml +34 -17
- package/agents/istio/istio-ambient-mesh-review-agent/harnesses/copilot.agent.md +26 -20
- package/agents/istio/istio-ambient-mesh-review-agent/harnesses/cursor.agent.md +20 -20
- package/agents/istio/istio-ambient-mesh-review-agent/harnesses/gemini.agent.md +20 -20
- package/agents/istio/istio-ambient-mesh-review-agent/harnesses/kiro-cli.agent.json +2 -2
- package/agents/istio/istio-ambient-mesh-review-agent/harnesses/kiro-ide.agent.md +20 -20
- package/agents/istio/istio-ambient-mesh-review-agent/metadata.json +29 -9
- package/agents/istio/istio-authorization-policy-review-agent/AGENT.md +51 -0
- package/agents/istio/istio-authorization-policy-review-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/istio/istio-authorization-policy-review-agent/harnesses/codex.toml +49 -0
- package/agents/istio/istio-authorization-policy-review-agent/harnesses/copilot.agent.md +44 -0
- package/agents/istio/istio-authorization-policy-review-agent/harnesses/cursor.agent.md +38 -0
- package/agents/istio/istio-authorization-policy-review-agent/harnesses/gemini.agent.md +38 -0
- package/agents/istio/istio-authorization-policy-review-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/istio/istio-authorization-policy-review-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/istio/istio-authorization-policy-review-agent/metadata.json +50 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/AGENT.md +51 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/harnesses/codex.toml +49 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/harnesses/copilot.agent.md +44 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/harnesses/cursor.agent.md +38 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/harnesses/gemini.agent.md +38 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/istio/istio-dataplane-diagnostics-agent/metadata.json +50 -0
- package/agents/istio/istio-gateway-api-review-agent/AGENT.md +51 -0
- package/agents/istio/istio-gateway-api-review-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/istio/istio-gateway-api-review-agent/harnesses/codex.toml +49 -0
- package/agents/istio/istio-gateway-api-review-agent/harnesses/copilot.agent.md +44 -0
- package/agents/istio/istio-gateway-api-review-agent/harnesses/cursor.agent.md +38 -0
- package/agents/istio/istio-gateway-api-review-agent/harnesses/gemini.agent.md +38 -0
- package/agents/istio/istio-gateway-api-review-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/istio/istio-gateway-api-review-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/istio/istio-gateway-api-review-agent/metadata.json +50 -0
- package/agents/istio/istio-maestro-agent/AGENT.md +51 -0
- package/agents/istio/istio-maestro-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/istio/istio-maestro-agent/harnesses/codex.toml +49 -0
- package/agents/istio/istio-maestro-agent/harnesses/copilot.agent.md +44 -0
- package/agents/istio/istio-maestro-agent/harnesses/cursor.agent.md +38 -0
- package/agents/istio/istio-maestro-agent/harnesses/gemini.agent.md +38 -0
- package/agents/istio/istio-maestro-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/istio/istio-maestro-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/istio/istio-maestro-agent/metadata.json +44 -0
- package/agents/istio/istio-traffic-resilience-review-agent/AGENT.md +51 -0
- package/agents/istio/istio-traffic-resilience-review-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/istio/istio-traffic-resilience-review-agent/harnesses/codex.toml +49 -0
- package/agents/istio/istio-traffic-resilience-review-agent/harnesses/copilot.agent.md +44 -0
- package/agents/istio/istio-traffic-resilience-review-agent/harnesses/cursor.agent.md +38 -0
- package/agents/istio/istio-traffic-resilience-review-agent/harnesses/gemini.agent.md +38 -0
- package/agents/istio/istio-traffic-resilience-review-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/istio/istio-traffic-resilience-review-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/istio/istio-traffic-resilience-review-agent/metadata.json +50 -0
- package/agents/istio/istio-upgrade-readiness-agent/AGENT.md +51 -0
- package/agents/istio/istio-upgrade-readiness-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/istio/istio-upgrade-readiness-agent/harnesses/codex.toml +49 -0
- package/agents/istio/istio-upgrade-readiness-agent/harnesses/copilot.agent.md +44 -0
- package/agents/istio/istio-upgrade-readiness-agent/harnesses/cursor.agent.md +38 -0
- package/agents/istio/istio-upgrade-readiness-agent/harnesses/gemini.agent.md +38 -0
- package/agents/istio/istio-upgrade-readiness-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/istio/istio-upgrade-readiness-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/istio/istio-upgrade-readiness-agent/metadata.json +50 -0
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/AGENT.md +23 -34
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/harnesses/claude-code.agent.md +23 -30
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/harnesses/codex.toml +46 -21
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/harnesses/copilot.agent.md +33 -30
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/harnesses/cursor.agent.md +23 -30
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/harnesses/gemini.agent.md +23 -30
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/harnesses/kiro-cli.agent.json +2 -2
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/harnesses/kiro-ide.agent.md +23 -30
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/metadata.json +9 -8
- package/agents/kubernetes/kubernetes-live-mesh-policy-guard-agent/references/rbac-pre-flight.md +9 -2
- package/agents/ovhcloud/ovhcloud-cost-finops-analyst-agent/metadata.json +17 -3
- package/agents/ovhcloud/ovhcloud-iam-policy-review-agent/metadata.json +17 -3
- package/agents/ovhcloud/ovhcloud-kubernetes-platform-operator-agent/metadata.json +17 -3
- package/agents/ovhcloud/ovhcloud-live-kms-key-destruction-guard-agent/metadata.json +17 -3
- package/agents/ovhcloud/ovhcloud-maestro-agent/metadata.json +17 -3
- package/agents/ovhcloud/ovhcloud-network-architect-agent/metadata.json +17 -3
- package/agents/scaleway/scaleway-cost-optimizer-agent/metadata.json +17 -3
- package/agents/scaleway/scaleway-iam-policy-review-agent/metadata.json +17 -3
- package/agents/scaleway/scaleway-kapsule-platform-operator-agent/metadata.json +17 -3
- package/agents/scaleway/scaleway-live-kapsule-rollout-guard-agent/metadata.json +17 -3
- package/agents/scaleway/scaleway-maestro-agent/metadata.json +17 -3
- package/agents/scaleway/scaleway-network-architect-agent/metadata.json +17 -3
- package/catalog/agents.json +378 -113
- package/catalog/asset-integrity.json +1268 -138
- package/catalog/install-roles.json +14 -1
- package/catalog/model-assignments.json +198 -0
- package/catalog/model-registry.json +70 -34
- package/catalog/skill-manifest.json +517 -13
- package/catalog/skills.json +213 -8
- package/catalog/workflows.json +49 -0
- package/package.json +7 -4
- package/plugins/cross-platform-agent-template/LICENSE +201 -0
- package/plugins/cross-platform-agent-template/README.md +30 -0
- package/plugins/cross-platform-agent-template/SECURITY.md +18 -0
- package/plugins/vanguard-frontier-agentic/.codex-plugin/plugin.json +1 -1
- package/powers/README.md +5 -2
- package/powers/vanguard-istio/POWER.md +6 -5
- package/schemas/istio-review-contract.schema.json +284 -0
- package/schemas/model-policy.schema.json +1 -1
- package/scripts/generate-board-counts.mjs +40 -4
- package/scripts/generate-readme-counts.mjs +51 -2
- package/scripts/generate-workflow-catalog.mjs +7 -7
- package/scripts/istio_evidence_facts.py +359 -0
- package/scripts/model-policy.mjs +74 -11
- package/skills/istio/README.md +15 -4
- package/skills/istio/istio-ambient-mesh-review/SKILL.md +38 -39
- package/skills/istio/istio-ambient-mesh-review/agents/openai.yaml +5 -0
- package/skills/istio/istio-ambient-mesh-review/metadata.json +8 -8
- package/skills/istio/istio-ambient-mesh-review/references/applicability.md +9 -0
- package/skills/istio/istio-ambient-mesh-review/references/enforcement-rules.md +21 -0
- package/skills/istio/istio-ambient-mesh-review/references/enrollment-and-paths.md +27 -0
- package/skills/istio/istio-ambient-mesh-review/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-ambient-mesh-review/references/migration-boundaries.md +19 -0
- package/skills/istio/istio-ambient-mesh-review/references/negative-tests.md +15 -0
- package/skills/istio/istio-ambient-mesh-review/references/official-sources.md +33 -32
- package/skills/istio/istio-ambient-mesh-review/references/output-contract.md +21 -0
- package/skills/istio/istio-ambient-mesh-review/references/review-contract.json +284 -0
- package/skills/istio/istio-authorization-policy-review/SKILL.md +44 -0
- package/skills/istio/istio-authorization-policy-review/agents/openai.yaml +5 -0
- package/skills/istio/istio-authorization-policy-review/metadata.json +30 -0
- package/skills/istio/istio-authorization-policy-review/references/applicability.md +9 -0
- package/skills/istio/istio-authorization-policy-review/references/authentication-and-identity.md +21 -0
- package/skills/istio/istio-authorization-policy-review/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-authorization-policy-review/references/negative-tests.md +15 -0
- package/skills/istio/istio-authorization-policy-review/references/official-sources.md +33 -0
- package/skills/istio/istio-authorization-policy-review/references/output-contract.md +21 -0
- package/skills/istio/istio-authorization-policy-review/references/policy-set-semantics.md +21 -0
- package/skills/istio/istio-authorization-policy-review/references/protocol-and-normalization.md +19 -0
- package/skills/istio/istio-authorization-policy-review/references/review-contract.json +284 -0
- package/skills/istio/istio-dataplane-diagnostics/SKILL.md +45 -0
- package/skills/istio/istio-dataplane-diagnostics/agents/openai.yaml +5 -0
- package/skills/istio/istio-dataplane-diagnostics/metadata.json +30 -0
- package/skills/istio/istio-dataplane-diagnostics/references/applicability.md +9 -0
- package/skills/istio/istio-dataplane-diagnostics/references/collection-and-offline-analysis.md +17 -0
- package/skills/istio/istio-dataplane-diagnostics/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-dataplane-diagnostics/references/hypothesis-workflow.md +19 -0
- package/skills/istio/istio-dataplane-diagnostics/references/negative-tests.md +13 -0
- package/skills/istio/istio-dataplane-diagnostics/references/official-sources.md +33 -0
- package/skills/istio/istio-dataplane-diagnostics/references/output-contract.md +21 -0
- package/skills/istio/istio-dataplane-diagnostics/references/review-contract.json +284 -0
- package/skills/istio/istio-dataplane-diagnostics/references/signal-interpretation.md +15 -0
- package/skills/istio/istio-gateway-api-review/SKILL.md +45 -0
- package/skills/istio/istio-gateway-api-review/agents/openai.yaml +5 -0
- package/skills/istio/istio-gateway-api-review/metadata.json +30 -0
- package/skills/istio/istio-gateway-api-review/references/applicability.md +9 -0
- package/skills/istio/istio-gateway-api-review/references/attachment-graph.md +19 -0
- package/skills/istio/istio-gateway-api-review/references/conditions-and-freshness.md +15 -0
- package/skills/istio/istio-gateway-api-review/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-gateway-api-review/references/negative-tests.md +12 -0
- package/skills/istio/istio-gateway-api-review/references/official-sources.md +33 -0
- package/skills/istio/istio-gateway-api-review/references/output-contract.md +21 -0
- package/skills/istio/istio-gateway-api-review/references/review-contract.json +284 -0
- package/skills/istio/istio-gateway-api-review/references/tls-and-boundaries.md +17 -0
- package/skills/istio/istio-live-policy-change/SKILL.md +45 -0
- package/skills/istio/istio-live-policy-change/agents/openai.yaml +7 -0
- package/skills/istio/istio-live-policy-change/metadata.json +29 -0
- package/skills/istio/istio-live-policy-change/references/applicability.md +9 -0
- package/skills/istio/istio-live-policy-change/references/approval-and-scope.md +17 -0
- package/skills/istio/istio-live-policy-change/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-live-policy-change/references/execution-protocol.md +19 -0
- package/skills/istio/istio-live-policy-change/references/negative-tests.md +12 -0
- package/skills/istio/istio-live-policy-change/references/official-sources.md +27 -0
- package/skills/istio/istio-live-policy-change/references/output-contract.md +21 -0
- package/skills/istio/istio-live-policy-change/references/review-contract.json +284 -0
- package/skills/istio/istio-live-policy-change/references/rollback-and-verification.md +19 -0
- package/skills/istio/istio-review-routing/SKILL.md +45 -0
- package/skills/istio/istio-review-routing/agents/openai.yaml +5 -0
- package/skills/istio/istio-review-routing/metadata.json +26 -0
- package/skills/istio/istio-review-routing/references/aggregation-and-conflicts.md +15 -0
- package/skills/istio/istio-review-routing/references/applicability.md +9 -0
- package/skills/istio/istio-review-routing/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-review-routing/references/live-handoff.md +11 -0
- package/skills/istio/istio-review-routing/references/negative-tests.md +11 -0
- package/skills/istio/istio-review-routing/references/official-sources.md +9 -0
- package/skills/istio/istio-review-routing/references/output-contract.md +21 -0
- package/skills/istio/istio-review-routing/references/review-contract.json +284 -0
- package/skills/istio/istio-review-routing/references/routing-table.md +18 -0
- package/skills/istio/istio-traffic-resilience-review/SKILL.md +45 -0
- package/skills/istio/istio-traffic-resilience-review/agents/openai.yaml +5 -0
- package/skills/istio/istio-traffic-resilience-review/metadata.json +30 -0
- package/skills/istio/istio-traffic-resilience-review/references/applicability.md +9 -0
- package/skills/istio/istio-traffic-resilience-review/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-traffic-resilience-review/references/mirroring-and-faults.md +15 -0
- package/skills/istio/istio-traffic-resilience-review/references/negative-tests.md +14 -0
- package/skills/istio/istio-traffic-resilience-review/references/official-sources.md +33 -0
- package/skills/istio/istio-traffic-resilience-review/references/output-contract.md +21 -0
- package/skills/istio/istio-traffic-resilience-review/references/review-contract.json +284 -0
- package/skills/istio/istio-traffic-resilience-review/references/routing-and-weights.md +19 -0
- package/skills/istio/istio-traffic-resilience-review/references/timeouts-retries-and-capacity.md +21 -0
- package/skills/istio/istio-upgrade-readiness/SKILL.md +45 -0
- package/skills/istio/istio-upgrade-readiness/agents/openai.yaml +5 -0
- package/skills/istio/istio-upgrade-readiness/metadata.json +30 -0
- package/skills/istio/istio-upgrade-readiness/references/applicability.md +9 -0
- package/skills/istio/istio-upgrade-readiness/references/crds-extensions-and-rollback.md +17 -0
- package/skills/istio/istio-upgrade-readiness/references/evidence-boundary.md +33 -0
- package/skills/istio/istio-upgrade-readiness/references/inventory-and-support.md +17 -0
- package/skills/istio/istio-upgrade-readiness/references/negative-tests.md +13 -0
- package/skills/istio/istio-upgrade-readiness/references/official-sources.md +33 -0
- package/skills/istio/istio-upgrade-readiness/references/output-contract.md +21 -0
- package/skills/istio/istio-upgrade-readiness/references/review-contract.json +284 -0
- package/skills/istio/istio-upgrade-readiness/references/skew-and-order.md +19 -0
- package/tests/fixtures/README.md +1 -1
- package/tests/fixtures/istio-maestro-routing/expected/001-happy-ambient-mesh-review.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/002-happy-authorization-policy-review.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/003-happy-dataplane-diagnostics.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/004-happy-gateway-api-review.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/005-happy-traffic-resilience-review.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/006-happy-upgrade-readiness.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/adv-ambiguous.json +4 -0
- package/tests/fixtures/istio-maestro-routing/expected/adv-instruction-injection.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/adv-liveguard-01-kubernetes-live-mesh-policy-guard.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/adv-persona-replacement.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/adv-secrets-bait.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-create-authorization-policy.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-istio-gateway-apply.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-kubectl-file-apply.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-label-peer-authentication.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-multiline-patch.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-qualified-plural-delete.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-resource-first-apply.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/live-set-peer-authentication.json +6 -0
- package/tests/fixtures/istio-maestro-routing/expected/negative-product-identification.json +4 -0
- package/tests/fixtures/istio-maestro-routing/expected/negative-review-apply-safety.json +6 -0
- package/tests/fixtures/istio-maestro-routing/inputs/001-happy-ambient-mesh-review.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/002-happy-authorization-policy-review.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/003-happy-dataplane-diagnostics.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/004-happy-gateway-api-review.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/005-happy-traffic-resilience-review.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/006-happy-upgrade-readiness.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/adv-ambiguous.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/adv-instruction-injection.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/adv-liveguard-01-kubernetes-live-mesh-policy-guard.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/adv-persona-replacement.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/adv-secrets-bait.json +7 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-create-authorization-policy.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-istio-gateway-apply.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-kubectl-file-apply.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-label-peer-authentication.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-multiline-patch.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-qualified-plural-delete.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-resource-first-apply.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/live-set-peer-authentication.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/negative-product-identification.json +8 -0
- package/tests/fixtures/istio-maestro-routing/inputs/negative-review-apply-safety.json +8 -0
- package/tests/fixtures/istio-maestro-routing/taxonomy.json +129 -0
- package/tests/fixtures/istio-review-evals/README.md +11 -0
- package/tests/fixtures/istio-review-evals/expected/AMB-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AMB-02.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AMB-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AMB-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AMB-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AMB-06.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AMB-07.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-02A.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-02B.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-06.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-07.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/AUTH-08.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/DIAG-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/DIAG-02.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/DIAG-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/DIAG-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/DIAG-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GATEWAY-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GATEWAY-02A.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GATEWAY-02B.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GATEWAY-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GATEWAY-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GATEWAY-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GUARD-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GUARD-02.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GUARD-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GUARD-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GUARD-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/GUARD-06.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/ROUTE-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/ROUTE-02.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/ROUTE-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/ROUTE-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/ROUTE-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/SAFETY-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/SAFETY-02.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-01A.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-01B.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-02.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-06.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/TRAFFIC-07.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/UPGRADE-01.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/UPGRADE-02A.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/UPGRADE-02B.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/UPGRADE-03.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/UPGRADE-04.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/UPGRADE-05.json +24 -0
- package/tests/fixtures/istio-review-evals/expected/UPGRADE-06.json +24 -0
- package/tests/fixtures/istio-review-evals/inputs/AMB-01.json +20 -0
- package/tests/fixtures/istio-review-evals/inputs/AMB-02.json +22 -0
- package/tests/fixtures/istio-review-evals/inputs/AMB-03.json +39 -0
- package/tests/fixtures/istio-review-evals/inputs/AMB-04.json +21 -0
- package/tests/fixtures/istio-review-evals/inputs/AMB-05.json +20 -0
- package/tests/fixtures/istio-review-evals/inputs/AMB-06.json +19 -0
- package/tests/fixtures/istio-review-evals/inputs/AMB-07.json +17 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-01.json +27 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-02A.json +22 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-02B.json +19 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-03.json +30 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-04.json +23 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-05.json +22 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-06.json +22 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-07.json +30 -0
- package/tests/fixtures/istio-review-evals/inputs/AUTH-08.json +21 -0
- package/tests/fixtures/istio-review-evals/inputs/DIAG-01.json +18 -0
- package/tests/fixtures/istio-review-evals/inputs/DIAG-02.json +14 -0
- package/tests/fixtures/istio-review-evals/inputs/DIAG-03.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/DIAG-04.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/DIAG-05.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/GATEWAY-01.json +29 -0
- package/tests/fixtures/istio-review-evals/inputs/GATEWAY-02A.json +21 -0
- package/tests/fixtures/istio-review-evals/inputs/GATEWAY-02B.json +17 -0
- package/tests/fixtures/istio-review-evals/inputs/GATEWAY-03.json +22 -0
- package/tests/fixtures/istio-review-evals/inputs/GATEWAY-04.json +22 -0
- package/tests/fixtures/istio-review-evals/inputs/GATEWAY-05.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/GUARD-01.json +19 -0
- package/tests/fixtures/istio-review-evals/inputs/GUARD-02.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/GUARD-03.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/GUARD-04.json +20 -0
- package/tests/fixtures/istio-review-evals/inputs/GUARD-05.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/GUARD-06.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/ROUTE-01.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/ROUTE-02.json +18 -0
- package/tests/fixtures/istio-review-evals/inputs/ROUTE-03.json +15 -0
- package/tests/fixtures/istio-review-evals/inputs/ROUTE-04.json +25 -0
- package/tests/fixtures/istio-review-evals/inputs/ROUTE-05.json +15 -0
- package/tests/fixtures/istio-review-evals/inputs/SAFETY-01.json +14 -0
- package/tests/fixtures/istio-review-evals/inputs/SAFETY-02.json +15 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-01A.json +23 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-01B.json +17 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-02.json +19 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-03.json +28 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-04.json +18 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-05.json +18 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-06.json +18 -0
- package/tests/fixtures/istio-review-evals/inputs/TRAFFIC-07.json +17 -0
- package/tests/fixtures/istio-review-evals/inputs/UPGRADE-01.json +19 -0
- package/tests/fixtures/istio-review-evals/inputs/UPGRADE-02A.json +23 -0
- package/tests/fixtures/istio-review-evals/inputs/UPGRADE-02B.json +17 -0
- package/tests/fixtures/istio-review-evals/inputs/UPGRADE-03.json +21 -0
- package/tests/fixtures/istio-review-evals/inputs/UPGRADE-04.json +16 -0
- package/tests/fixtures/istio-review-evals/inputs/UPGRADE-05.json +33 -0
- package/tests/fixtures/istio-review-evals/inputs/UPGRADE-06.json +17 -0
- package/tests/fixtures/istio-review-evals/manifest.json +337 -0
- package/tests/fixtures/runtime-semantics/README.md +3 -0
- package/tests/fixtures/runtime-semantics/RUNTIME-AMB-L7.json +35 -0
- package/tests/fixtures/runtime-semantics/RUNTIME-AUTH-EMPTY.json +33 -0
- package/tests/fixtures/runtime-semantics/RUNTIME-GATEWAY.json +35 -0
- package/tests/fixtures/runtime-semantics/RUNTIME-JWT.json +34 -0
- package/tests/fixtures/runtime-semantics/RUNTIME-MIGRATION.json +35 -0
- package/tests/fixtures/runtime-semantics/RUNTIME-MIRROR.json +33 -0
- package/tests/fixtures/runtime-semantics/RUNTIME-UPGRADE.json +34 -0
- package/tests/integration/rbac-pre-flight/guards/mesh-policy.sh +9 -2
- package/tests/istio-review-suite/test_contract.py +121 -0
- package/tests/istio-review-suite/test_evidence_facts.py +344 -0
- package/tests/validate-catalog.py +156 -0
- package/tests/validate-model-params.py +161 -0
- package/tests/validate-readme-counts.mjs +58 -2
- package/tests/validate-release-notes.mjs +35 -0
- package/skills/istio/istio-ambient-mesh-review/references/mcp-and-evidence.md +0 -59
- package/skills/istio/istio-ambient-mesh-review/references/workflow-and-output.md +0 -128
|
@@ -342,6 +342,154 @@ def validate_guarded_live_kubernetes_agents() -> None:
|
|
|
342
342
|
)
|
|
343
343
|
|
|
344
344
|
|
|
345
|
+
# Adapter files that prove a harness actually ships, mapped to the `harnesses` value
|
|
346
|
+
# that must then be declared.
|
|
347
|
+
HARNESS_ADAPTER_FILES = {
|
|
348
|
+
"codex.toml": "codex",
|
|
349
|
+
"copilot.agent.md": "copilot",
|
|
350
|
+
"claude-code.agent.md": "claude-code",
|
|
351
|
+
"cursor.agent.md": "cursor",
|
|
352
|
+
"gemini.agent.md": "gemini",
|
|
353
|
+
"kiro-ide.agent.md": "kiro",
|
|
354
|
+
"kiro-cli.agent.json": "kiro",
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
# Kiro is the one harness whose single `harnesses` value covers TWO adapter files, and the
|
|
358
|
+
# exporter emits both. Collapsing them into one set member would let a half-shipped Kiro
|
|
359
|
+
# adapter pass: with only kiro-ide.agent.md present, `kiro` is still in the on-disk set, the
|
|
360
|
+
# declaration matches, and the export later fails on the missing kiro-cli.agent.json. So the
|
|
361
|
+
# pair is checked explicitly rather than through the collapsed mapping.
|
|
362
|
+
KIRO_REQUIRED_FILES = ("kiro-ide.agent.md", "kiro-cli.agent.json")
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def validate_harness_declarations() -> None:
|
|
366
|
+
"""Every agent's `harnesses` must match the adapters it ships AND the catalog entry.
|
|
367
|
+
|
|
368
|
+
Three independent failures, each of which has actually happened or was one edit away:
|
|
369
|
+
|
|
370
|
+
* UNDER-declared (adapter on disk, harness absent from `harnesses`) makes a shipped
|
|
371
|
+
adapter invisible to everything that filters on the catalog. ionos, ovhcloud, and
|
|
372
|
+
scaleway each shipped all seven adapter files while declaring only codex and
|
|
373
|
+
claude-code, so generate-cursor-plugin.mjs omitted 18 real cursor adapters and
|
|
374
|
+
generate-kiro-powers.mjs dropped three real Kiro Powers.
|
|
375
|
+
|
|
376
|
+
* OVER-declared (harness claimed, no adapter file) promises an install path that does
|
|
377
|
+
not exist, failing at the user's `vfa-export-agents` rather than here.
|
|
378
|
+
|
|
379
|
+
* CATALOG DRIFT (metadata.json and catalog/agents.json disagree). catalog/agents.json
|
|
380
|
+
has no full regenerator — only an upsert — so fixing metadata.json does NOT update
|
|
381
|
+
it, and the catalog is what every generator actually reads. Checking metadata
|
|
382
|
+
against disk alone would report success while the original user-facing breakage
|
|
383
|
+
remained. This is not hypothetical: resyncing those 18 catalog entries was a
|
|
384
|
+
separate manual step from fixing their metadata.
|
|
385
|
+
"""
|
|
386
|
+
problems: list[str] = []
|
|
387
|
+
|
|
388
|
+
catalog_harnesses: dict[str, list] = {}
|
|
389
|
+
catalog_agents = load_json(ROOT / "catalog" / "agents.json")
|
|
390
|
+
if isinstance(catalog_agents, dict):
|
|
391
|
+
catalog_agents = catalog_agents.get("agents", [])
|
|
392
|
+
for entry in catalog_agents:
|
|
393
|
+
if isinstance(entry, dict) and entry.get("type") == "agent":
|
|
394
|
+
catalog_harnesses[entry["id"]] = entry.get("harnesses") or []
|
|
395
|
+
|
|
396
|
+
for metadata_path in sorted(ROOT.glob("agents/*/*/metadata.json")):
|
|
397
|
+
data = load_json(metadata_path)
|
|
398
|
+
agent_id = data.get("id", metadata_path.parent.name)
|
|
399
|
+
declared = set(data.get("harnesses") or [])
|
|
400
|
+
harness_dir = metadata_path.parent / "harnesses"
|
|
401
|
+
present_files = (
|
|
402
|
+
{entry.name for entry in harness_dir.iterdir() if entry.is_file()}
|
|
403
|
+
if harness_dir.is_dir()
|
|
404
|
+
else set()
|
|
405
|
+
)
|
|
406
|
+
on_disk = {
|
|
407
|
+
HARNESS_ADAPTER_FILES[name]
|
|
408
|
+
for name in present_files
|
|
409
|
+
if name in HARNESS_ADAPTER_FILES
|
|
410
|
+
}
|
|
411
|
+
# "other" is a catalog-only escape hatch with no adapter file of its own.
|
|
412
|
+
declared.discard("other")
|
|
413
|
+
|
|
414
|
+
if on_disk - declared:
|
|
415
|
+
problems.append(
|
|
416
|
+
f"{agent_id}: ships adapters for {sorted(on_disk - declared)} "
|
|
417
|
+
f"but does not declare them in harnesses"
|
|
418
|
+
)
|
|
419
|
+
if declared - on_disk:
|
|
420
|
+
problems.append(
|
|
421
|
+
f"{agent_id}: declares harnesses {sorted(declared - on_disk)} "
|
|
422
|
+
f"with no matching adapter file"
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
# Kiro's two adapter files are checked as a pair, not through the collapsed value.
|
|
426
|
+
kiro_missing = [f for f in KIRO_REQUIRED_FILES if f not in present_files]
|
|
427
|
+
if "kiro" in declared and kiro_missing:
|
|
428
|
+
problems.append(
|
|
429
|
+
f"{agent_id}: declares the kiro harness but is missing {sorted(kiro_missing)} "
|
|
430
|
+
f"— both Kiro adapter files are required"
|
|
431
|
+
)
|
|
432
|
+
if kiro_missing and len(kiro_missing) == 1:
|
|
433
|
+
problems.append(
|
|
434
|
+
f"{agent_id}: ships a partial Kiro adapter — has "
|
|
435
|
+
f"{sorted(set(KIRO_REQUIRED_FILES) - set(kiro_missing))}, missing {kiro_missing}"
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
# The catalog is what the generators read; metadata alone proves nothing about them.
|
|
439
|
+
if agent_id in catalog_harnesses:
|
|
440
|
+
if sorted(catalog_harnesses[agent_id]) != sorted(data.get("harnesses") or []):
|
|
441
|
+
problems.append(
|
|
442
|
+
f"{agent_id}: catalog/agents.json declares "
|
|
443
|
+
f"{sorted(catalog_harnesses[agent_id])} but metadata.json declares "
|
|
444
|
+
f"{sorted(data.get('harnesses') or [])} — resync the catalog entry"
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
assert_true(
|
|
448
|
+
not problems,
|
|
449
|
+
"harness declarations disagree with shipped adapters or the catalog:\n - "
|
|
450
|
+
+ "\n - ".join(problems),
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def validate_tui_provider_enum() -> None:
|
|
455
|
+
"""Every catalog provider must have a variant in the vfa-tui `Provider` enum.
|
|
456
|
+
|
|
457
|
+
tools/vfa-tui deserializes catalog/agents.json into a serde enum with
|
|
458
|
+
`deny_unknown_fields`, so a provider the enum does not know makes the whole catalog
|
|
459
|
+
fail to load and the TUI unusable. A Rust test already asserts this — but CI's
|
|
460
|
+
vfa-tui workflow is path-filtered to `tools/vfa-tui/**` (see
|
|
461
|
+
.github/workflows/vfa-tui-ci.yml), so a catalog-only PR that adds a provider never
|
|
462
|
+
triggers it and merges green while leaving the TUI broken. CLAUDE.md documents that
|
|
463
|
+
trap and asks contributors to remember `cargo test`; this makes remembering
|
|
464
|
+
unnecessary, because `npm run validate` is not path-filtered.
|
|
465
|
+
|
|
466
|
+
Parsed, never executed: variant names are read with a regex and converted to the
|
|
467
|
+
kebab-case slugs serde produces via `rename_all`, plus any explicit `rename = "..."`.
|
|
468
|
+
"""
|
|
469
|
+
enum_path = ROOT / "tools" / "vfa-tui" / "src" / "models" / "provider.rs"
|
|
470
|
+
if not enum_path.exists():
|
|
471
|
+
# The TUI is optional to the catalog's correctness; absence is not a catalog error.
|
|
472
|
+
return
|
|
473
|
+
source = enum_path.read_text(encoding="utf8")
|
|
474
|
+
variants = re.findall(r"^\s{4}([A-Z][A-Za-z0-9]*),\s*$", source, re.MULTILINE)
|
|
475
|
+
slugs = {re.sub(r"(?<!^)(?=[A-Z])", "-", v).lower() for v in variants}
|
|
476
|
+
slugs |= set(re.findall(r'rename\s*=\s*"([a-z0-9-]+)"', source))
|
|
477
|
+
|
|
478
|
+
providers = set()
|
|
479
|
+
for entry in load_json(ROOT / "catalog" / "agents.json"):
|
|
480
|
+
if isinstance(entry, dict) and entry.get("provider"):
|
|
481
|
+
providers.add(entry["provider"])
|
|
482
|
+
|
|
483
|
+
missing = sorted(providers - slugs)
|
|
484
|
+
assert_true(
|
|
485
|
+
not missing,
|
|
486
|
+
"catalog providers with no variant in tools/vfa-tui/src/models/provider.rs: "
|
|
487
|
+
+ f"{missing}. The TUI deserializes catalog/agents.json with a strict enum, so "
|
|
488
|
+
+ "the catalog will fail to load entirely. Add the variant (kebab-case serde) and "
|
|
489
|
+
+ "run `cargo test` in tools/vfa-tui.",
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
|
|
345
493
|
def main() -> int:
|
|
346
494
|
errors: list[str] = []
|
|
347
495
|
seen_ids: set[str] = set()
|
|
@@ -364,6 +512,14 @@ def main() -> int:
|
|
|
364
512
|
validate_codex_harness_adapters()
|
|
365
513
|
except AssertionError as exc:
|
|
366
514
|
errors.append(str(exc))
|
|
515
|
+
try:
|
|
516
|
+
validate_harness_declarations()
|
|
517
|
+
except AssertionError as exc:
|
|
518
|
+
errors.append(str(exc))
|
|
519
|
+
try:
|
|
520
|
+
validate_tui_provider_enum()
|
|
521
|
+
except AssertionError as exc:
|
|
522
|
+
errors.append(str(exc))
|
|
367
523
|
try:
|
|
368
524
|
validate_markdown_agent_templates()
|
|
369
525
|
except AssertionError as exc:
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Gate: Cursor per-model parameter groups are accepted or rejected correctly.
|
|
3
|
+
|
|
4
|
+
`scripts/model-policy.mjs` accepts Cursor's documented per-model parameter
|
|
5
|
+
group appended to a model id in square brackets, e.g.
|
|
6
|
+
|
|
7
|
+
claude-opus-5[effort=high,context=300k]
|
|
8
|
+
|
|
9
|
+
The registry namespace pattern only shapes that group (a nested-quantifier
|
|
10
|
+
regex is rejected by the registry's own ReDoS guard), so the structure — the
|
|
11
|
+
documented keys, the key=value shape, and no duplicates — is enforced
|
|
12
|
+
semantically inside the script. `validate:model-policy` only runs `check`
|
|
13
|
+
against the committed policy, which exercises the accepting path alone; this
|
|
14
|
+
gate pins the rejecting paths too, so the semantic validation cannot quietly
|
|
15
|
+
stop working.
|
|
16
|
+
|
|
17
|
+
Every case runs through `set --dry-run`, which validates the resulting policy
|
|
18
|
+
without writing anything.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import re
|
|
25
|
+
import subprocess
|
|
26
|
+
import sys
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
REPO = Path(__file__).resolve().parent.parent
|
|
30
|
+
ENGINE = REPO / "scripts" / "model-policy.mjs"
|
|
31
|
+
POLICY_SCHEMA = REPO / "schemas" / "model-policy.schema.json"
|
|
32
|
+
|
|
33
|
+
# (model value, should_be_accepted, why)
|
|
34
|
+
CASES: list[tuple[str, bool, str]] = [
|
|
35
|
+
("composer-2.5", True, "bare registered id, no parameter group"),
|
|
36
|
+
("claude-opus-5[effort=high]", True, "single documented key"),
|
|
37
|
+
("gpt-5.6-sol[effort=high,context=300k]", True, "two documented keys"),
|
|
38
|
+
("composer-2[fast=false]", True, "the fast key, boolean-ish value"),
|
|
39
|
+
("claude-opus-5[bogus=1]", False, "undocumented key"),
|
|
40
|
+
("claude-opus-5[effort=high,bogus=1]", False, "one good key, one undocumented"),
|
|
41
|
+
("claude-opus-5[effort]", False, "missing =value"),
|
|
42
|
+
("claude-opus-5[=high]", False, "missing key"),
|
|
43
|
+
("claude-opus-5[effort=]", False, "empty value"),
|
|
44
|
+
("claude-opus-5[]", False, "empty parameter group"),
|
|
45
|
+
("claude-opus-5[effort=high,effort=low]", False, "duplicate key"),
|
|
46
|
+
("claude-opus-5[effort=high=low]", False, "two separators in one pair"),
|
|
47
|
+
("claude-opus-5[effort=high,context=300k=x]", False, "two separators in the second pair"),
|
|
48
|
+
("claude-opus-5[=]", False, "separator with neither key nor value"),
|
|
49
|
+
("not-a-registered-model[effort=high]", False, "base id absent from the allowlist"),
|
|
50
|
+
("claude-opus-5[a=1][b=2]", False, "two groups"),
|
|
51
|
+
("claude-opus-5[effort=high]trailing", False, "group not at the end"),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def pick_agent_id() -> str:
|
|
56
|
+
"""An agent id that exists in the catalog, so the scope resolves."""
|
|
57
|
+
agents = json.loads((REPO / "catalog" / "agents.json").read_text(encoding="utf-8"))
|
|
58
|
+
if not agents:
|
|
59
|
+
raise SystemExit("ERROR: catalog/agents.json is empty; cannot scope the probe")
|
|
60
|
+
return sorted(a["id"] for a in agents)[0]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def accepted(agent_id: str, model: str) -> tuple[bool, str]:
|
|
64
|
+
proc = subprocess.run(
|
|
65
|
+
[
|
|
66
|
+
"node",
|
|
67
|
+
str(ENGINE),
|
|
68
|
+
"set",
|
|
69
|
+
"--scope",
|
|
70
|
+
f"agent={agent_id}",
|
|
71
|
+
"--harness",
|
|
72
|
+
"cursor",
|
|
73
|
+
"--model",
|
|
74
|
+
model,
|
|
75
|
+
"--dry-run",
|
|
76
|
+
],
|
|
77
|
+
cwd=REPO,
|
|
78
|
+
capture_output=True,
|
|
79
|
+
text=True,
|
|
80
|
+
)
|
|
81
|
+
return proc.returncode == 0, (proc.stdout + proc.stderr).strip()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def schema_model_pattern() -> str:
|
|
85
|
+
"""The `model` pattern the policy schema declares for a rule."""
|
|
86
|
+
schema = json.loads(POLICY_SCHEMA.read_text(encoding="utf-8"))
|
|
87
|
+
return schema["properties"]["rules"]["items"]["properties"]["model"]["pattern"]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def check_schema_agrees(accepted_models: list[str]) -> list[str]:
|
|
91
|
+
"""The script and the schema must agree on what a rule may contain.
|
|
92
|
+
|
|
93
|
+
A non-dry-run `set` writes the model value straight into
|
|
94
|
+
`catalog/model-policy.json`. If the script accepts a value the schema's
|
|
95
|
+
`model` pattern rejects, every policy using it is invalid under its own
|
|
96
|
+
declared contract and a schema-aware consumer will refuse it — a mismatch
|
|
97
|
+
the script's own validator can never surface, which is why it is asserted
|
|
98
|
+
here rather than left to the engine.
|
|
99
|
+
"""
|
|
100
|
+
problems: list[str] = []
|
|
101
|
+
pattern = schema_model_pattern()
|
|
102
|
+
compiled = re.compile(pattern)
|
|
103
|
+
for model in accepted_models:
|
|
104
|
+
if not compiled.match(model):
|
|
105
|
+
problems.append(
|
|
106
|
+
f"schemas/model-policy.schema.json rejects {model!r}, which "
|
|
107
|
+
f"scripts/model-policy.mjs accepts (schema pattern: {pattern})"
|
|
108
|
+
)
|
|
109
|
+
# Values from other harnesses must keep working under the same pattern.
|
|
110
|
+
for model in ("qwen3:32b", "anthropic/claude-sonnet-4.5", "gpt-5.5", "auto", "inherit"):
|
|
111
|
+
if not compiled.match(model):
|
|
112
|
+
problems.append(
|
|
113
|
+
f"schemas/model-policy.schema.json rejects {model!r}, a value other "
|
|
114
|
+
f"harnesses rely on (schema pattern: {pattern})"
|
|
115
|
+
)
|
|
116
|
+
return problems
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def main() -> int:
|
|
120
|
+
agent_id = pick_agent_id()
|
|
121
|
+
failures: list[str] = []
|
|
122
|
+
|
|
123
|
+
for model, want_ok, why in CASES:
|
|
124
|
+
got_ok, output = accepted(agent_id, model)
|
|
125
|
+
if got_ok == want_ok:
|
|
126
|
+
verdict = "accepted" if got_ok else "rejected"
|
|
127
|
+
print(f"OK {verdict:8} {model} ({why})")
|
|
128
|
+
continue
|
|
129
|
+
wanted = "accepted" if want_ok else "rejected"
|
|
130
|
+
got = "accepted" if got_ok else "rejected"
|
|
131
|
+
failures.append(
|
|
132
|
+
f"{model!r} should have been {wanted} ({why}) but was {got}\n"
|
|
133
|
+
f" engine output: {output.splitlines()[-1] if output else '(none)'}"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# A rejection must say why, not just fail: an operator needs to know which
|
|
137
|
+
# key was wrong.
|
|
138
|
+
_, msg = accepted(agent_id, "claude-opus-5[bogus=1]")
|
|
139
|
+
if "bogus" not in msg or "parameter" not in msg:
|
|
140
|
+
failures.append(
|
|
141
|
+
"the rejection message for an undocumented key must name the key and "
|
|
142
|
+
f"mention the parameter group; got: {msg!r}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
failures.extend(check_schema_agrees([m for m, ok, _ in CASES if ok]))
|
|
146
|
+
|
|
147
|
+
if failures:
|
|
148
|
+
print("\nFAIL: model parameter-group validation drifted:", file=sys.stderr)
|
|
149
|
+
for f in failures:
|
|
150
|
+
print(f" - {f}", file=sys.stderr)
|
|
151
|
+
return 1
|
|
152
|
+
|
|
153
|
+
print(
|
|
154
|
+
f"\nOK: {len(CASES)} model parameter-group cases behave as documented, "
|
|
155
|
+
"and the policy schema accepts every value the script does"
|
|
156
|
+
)
|
|
157
|
+
return 0
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
if __name__ == "__main__":
|
|
161
|
+
sys.exit(main())
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* roles = number of keys under .roles in catalog/install-roles.json
|
|
11
11
|
* rules = length of JSON array in catalog/rules.json
|
|
12
12
|
* mcp = length of JSON array in catalog/mcp-references.json
|
|
13
|
+
* provider agents = metadata provider values under agents/
|
|
14
|
+
* domain skills = SKILL.md files under each skills/<domain>/ directory
|
|
13
15
|
*
|
|
14
16
|
* Run: node tests/validate-readme-counts.mjs
|
|
15
17
|
*/
|
|
@@ -45,19 +47,27 @@ function findFiles(dir, basename) {
|
|
|
45
47
|
|
|
46
48
|
const skillFiles = findFiles(path.join(repoRoot, "skills"), "SKILL.md");
|
|
47
49
|
const computedSkills = skillFiles.length;
|
|
50
|
+
const skillsPerDirectory = new Map();
|
|
51
|
+
for (const f of skillFiles) {
|
|
52
|
+
const directory = path.relative(path.join(repoRoot, "skills"), f).split(path.sep)[0];
|
|
53
|
+
skillsPerDirectory.set(directory, (skillsPerDirectory.get(directory) ?? 0) + 1);
|
|
54
|
+
}
|
|
48
55
|
|
|
49
56
|
const agentMetaFiles = findFiles(path.join(repoRoot, "agents"), "metadata.json");
|
|
50
57
|
const computedAgents = agentMetaFiles.length;
|
|
51
58
|
|
|
52
59
|
const providerSet = new Set();
|
|
60
|
+
const agentsPerProvider = new Map();
|
|
53
61
|
for (const f of agentMetaFiles) {
|
|
54
62
|
try {
|
|
55
63
|
const data = JSON.parse(fs.readFileSync(f, "utf8"));
|
|
56
64
|
if (typeof data.provider === "string" && data.provider.length > 0) {
|
|
57
65
|
providerSet.add(data.provider);
|
|
66
|
+
agentsPerProvider.set(data.provider, (agentsPerProvider.get(data.provider) ?? 0) + 1);
|
|
58
67
|
}
|
|
59
|
-
} catch {
|
|
60
|
-
|
|
68
|
+
} catch (error) {
|
|
69
|
+
process.stderr.write(`FAIL [readme-counts] malformed agent metadata ${f}: ${error.message}\n`);
|
|
70
|
+
process.exit(1);
|
|
61
71
|
}
|
|
62
72
|
}
|
|
63
73
|
const computedProviders = providerSet.size;
|
|
@@ -126,6 +136,22 @@ const labelToKey = {
|
|
|
126
136
|
|
|
127
137
|
const failures = [];
|
|
128
138
|
|
|
139
|
+
const requiredIstioMarkers = [
|
|
140
|
+
["Istio agent provider", /<!--\s*count:provider:istio\s*-->\d+<!--\s*\/count\s*-->/g],
|
|
141
|
+
[
|
|
142
|
+
"Istio skill directory",
|
|
143
|
+
/<!--\s*count:skill-directory:istio\s*-->\d+<!--\s*\/count\s*-->/g,
|
|
144
|
+
],
|
|
145
|
+
];
|
|
146
|
+
for (const [label, marker] of requiredIstioMarkers) {
|
|
147
|
+
const occurrences = readme.match(marker)?.length ?? 0;
|
|
148
|
+
if (occurrences !== 1) {
|
|
149
|
+
failures.push(
|
|
150
|
+
`FAIL [readme-counts] README must contain exactly one ${label} count marker; found ${occurrences}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
129
155
|
// Parse table rows: | Label | Number |
|
|
130
156
|
// Tolerate extra whitespace around cell content.
|
|
131
157
|
const tableRowRe = /\|\s*([^|]+?)\s*\|\s*(\d+)\s*\|/g;
|
|
@@ -161,6 +187,36 @@ while ((spanMatch = spanRe.exec(readme)) !== null) {
|
|
|
161
187
|
}
|
|
162
188
|
}
|
|
163
189
|
|
|
190
|
+
const providerSpanRe =
|
|
191
|
+
/<!--\s*count:provider:([a-z0-9-]+)\s*-->(\d+)<!--\s*\/count\s*-->/g;
|
|
192
|
+
while ((spanMatch = providerSpanRe.exec(readme)) !== null) {
|
|
193
|
+
const slug = spanMatch[1];
|
|
194
|
+
const shownValue = parseInt(spanMatch[2], 10);
|
|
195
|
+
const computedValue = agentsPerProvider.get(slug);
|
|
196
|
+
if (computedValue === undefined) {
|
|
197
|
+
failures.push(`FAIL [readme-counts] unknown agent provider marker: ${slug}`);
|
|
198
|
+
} else if (shownValue !== computedValue) {
|
|
199
|
+
failures.push(
|
|
200
|
+
`FAIL [readme-counts] provider ${slug}: README shows ${shownValue}, computed ${computedValue}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const skillDirectorySpanRe =
|
|
206
|
+
/<!--\s*count:skill-directory:([a-z0-9-]+)\s*-->(\d+)<!--\s*\/count\s*-->/g;
|
|
207
|
+
while ((spanMatch = skillDirectorySpanRe.exec(readme)) !== null) {
|
|
208
|
+
const slug = spanMatch[1];
|
|
209
|
+
const shownValue = parseInt(spanMatch[2], 10);
|
|
210
|
+
const computedValue = skillsPerDirectory.get(slug);
|
|
211
|
+
if (computedValue === undefined) {
|
|
212
|
+
failures.push(`FAIL [readme-counts] unknown skill directory marker: ${slug}`);
|
|
213
|
+
} else if (shownValue !== computedValue) {
|
|
214
|
+
failures.push(
|
|
215
|
+
`FAIL [readme-counts] skill directory ${slug}: README shows ${shownValue}, computed ${computedValue}`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
164
220
|
// ---------------------------------------------------------------------------
|
|
165
221
|
// Report
|
|
166
222
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { generateNotes } from "@semantic-release/release-notes-generator";
|
|
3
|
+
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
const config = require("../.releaserc.js");
|
|
6
|
+
const pluginConfig = config.plugins.find(
|
|
7
|
+
([name]) => name === "@semantic-release/release-notes-generator",
|
|
8
|
+
)?.[1];
|
|
9
|
+
|
|
10
|
+
if (!pluginConfig) {
|
|
11
|
+
throw new Error("release-notes-generator configuration is missing");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const notes = await generateNotes(pluginConfig, {
|
|
15
|
+
commits: [
|
|
16
|
+
{
|
|
17
|
+
hash: "1234567890abcdef",
|
|
18
|
+
message: "feat(istio): add evidence-bounded review suite",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
lastRelease: { gitTag: "v3.11.1", gitHead: "old" },
|
|
22
|
+
nextRelease: { version: "3.12.0", gitTag: "v3.12.0", gitHead: "new" },
|
|
23
|
+
options: {
|
|
24
|
+
repositoryUrl:
|
|
25
|
+
"https://github.com/VincentChuWaiChow/vanguard-frontier-agentic.git",
|
|
26
|
+
},
|
|
27
|
+
cwd: process.cwd(),
|
|
28
|
+
logger: console,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (!notes.includes("v3.12.0") || !notes.includes("evidence-bounded review suite")) {
|
|
32
|
+
throw new Error("release notes are missing the expected version or feature");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log("OK: semantic-release notes generated with the configured preset");
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# Evidence Path and Tooling
|
|
2
|
-
|
|
3
|
-
## Evidence path
|
|
4
|
-
|
|
5
|
-
1. Prefer live cluster evidence when a Kubernetes MCP server, `kubectl`, and `istioctl` are available against the mesh's primary cluster.
|
|
6
|
-
2. Fall back to the official Istio documentation (istio.io) for ambient/sidecar architecture, policy semantics, and CRD schema when live inspection is unavailable.
|
|
7
|
-
3. Ask only for sanitized YAML for the affected resources (`PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, `Gateway`, `VirtualService`, `DestinationRule`, `Sidecar`, namespace labels) when current-state proof matters.
|
|
8
|
-
4. Label conclusions as `live evidence`, `documentation-based`, `sanitized user evidence`, or `inference`.
|
|
9
|
-
|
|
10
|
-
## Useful live-evidence commands
|
|
11
|
-
|
|
12
|
-
```shell
|
|
13
|
-
# All Istio security and traffic policies across the cluster
|
|
14
|
-
kubectl get peerauthentication,authorizationpolicy,requestauthentication,gateway,virtualservice,destinationrule,sidecar -A -o yaml
|
|
15
|
-
|
|
16
|
-
# Confirm mesh mode (ambient vs sidecar) — namespace labels
|
|
17
|
-
kubectl get namespaces --show-labels | grep -E 'istio.io/dataplane-mode|istio-injection'
|
|
18
|
-
|
|
19
|
-
# Ambient: list waypoint deployments and bindings
|
|
20
|
-
kubectl get gateways.gateway.networking.k8s.io -A -l istio.io/waypoint-for
|
|
21
|
-
kubectl get pods -A -l gateway.networking.k8s.io/gateway-name
|
|
22
|
-
|
|
23
|
-
# Inspect ztunnel state on each node
|
|
24
|
-
kubectl -n istio-system get daemonset ztunnel
|
|
25
|
-
istioctl x ztunnel-config workload # what ztunnel sees as in-mesh workloads
|
|
26
|
-
istioctl x ztunnel-config policies # what L4 policies ztunnel is enforcing
|
|
27
|
-
istioctl x ztunnel-config services # service-to-workload mapping
|
|
28
|
-
|
|
29
|
-
# Validate proposed changes before applying
|
|
30
|
-
istioctl analyze -n <namespace>
|
|
31
|
-
istioctl analyze --recursive .
|
|
32
|
-
|
|
33
|
-
# For sidecar mode: which workloads have sidecars injected
|
|
34
|
-
kubectl get pods -A -o jsonpath='{range .items[?(@.metadata.annotations.sidecar\.istio\.io/inject!="false")]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'
|
|
35
|
-
|
|
36
|
-
# Inspect effective policy at a specific workload
|
|
37
|
-
istioctl proxy-config listener <pod>.<namespace>
|
|
38
|
-
istioctl proxy-config cluster <pod>.<namespace>
|
|
39
|
-
istioctl authz check <pod>.<namespace>
|
|
40
|
-
|
|
41
|
-
# Mesh control-plane state
|
|
42
|
-
kubectl -n istio-system get deploy istiod -o yaml
|
|
43
|
-
istioctl version
|
|
44
|
-
istioctl proxy-status
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Mesh state to confirm before review
|
|
48
|
-
|
|
49
|
-
- **Mesh mode per namespace** — sidecar (`istio-injection=enabled`), ambient (`istio.io/dataplane-mode=ambient`), or none. A single mesh can mix modes; conclusions differ.
|
|
50
|
-
- **Waypoint deployment for ambient namespaces** — `kubectl get gateways.gateway.networking.k8s.io -n <namespace> -l istio.io/waypoint-for`. Without a waypoint, L7 AuthorizationPolicy rules in that namespace are not enforced.
|
|
51
|
-
- **Istio version** (`istioctl version`) — ambient went GA in 1.24; older versions have different semantics.
|
|
52
|
-
- **Whether `PeerAuthentication` exists in the mesh root namespace** (default `istio-system` or whatever `meshConfig.rootNamespace` points to). Mesh-wide policies live there.
|
|
53
|
-
- **Whether multi-cluster (multi-primary or primary-remote)** is in use — `AuthorizationPolicy` evaluation crosses cluster boundaries when mesh networking is configured.
|
|
54
|
-
|
|
55
|
-
## Sanitization rules
|
|
56
|
-
|
|
57
|
-
- Never request kubeconfig contents, mesh root CA private keys, JWKs private keys, or workload service-account tokens.
|
|
58
|
-
- Replace identifiable cluster URLs, JWT issuer URLs (when sensitive), and namespace names with placeholders unless the user provides them.
|
|
59
|
-
- Do not print Istio root CA certificates beyond their public certificate body.
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
# Workflow and Output Contract
|
|
2
|
-
|
|
3
|
-
## Workflow
|
|
4
|
-
|
|
5
|
-
### Step 1 — Identify mesh mode for the affected namespaces
|
|
6
|
-
|
|
7
|
-
Istio supports three deployment modes that can coexist in one mesh. The review path differs based on mode.
|
|
8
|
-
|
|
9
|
-
1. **Sidecar mode** — pods have an Envoy sidecar injected. Namespace labeled `istio-injection=enabled`. All policy is enforced at the sidecar.
|
|
10
|
-
2. **Ambient mode** — no sidecars; ztunnel runs as a per-node DaemonSet for L4 zero-trust + optional waypoint proxies for L7. Namespace labeled `istio.io/dataplane-mode=ambient`.
|
|
11
|
-
3. **Mixed** — some workloads in a namespace use sidecars, others use ambient. Verify per-pod with annotations.
|
|
12
|
-
|
|
13
|
-
Reference: [Choosing between sidecar and ambient](https://istio.io/latest/docs/overview/dataplane-modes/) and [Ambient mode overview](https://istio.io/latest/docs/ambient/overview/).
|
|
14
|
-
|
|
15
|
-
### Step 2 — Confirm waypoint deployment for ambient namespaces (the L7 trap)
|
|
16
|
-
|
|
17
|
-
This is the most important ambient-specific check. Without a waypoint, L7 `AuthorizationPolicy` rules are silently ignored.
|
|
18
|
-
|
|
19
|
-
1. List waypoints: `kubectl get gateways.gateway.networking.k8s.io -n <namespace> -l istio.io/waypoint-for`.
|
|
20
|
-
2. Confirm the waypoint binding label on the namespace, ServiceAccount, or workload (`istio.io/use-waypoint: <waypoint-name>`).
|
|
21
|
-
3. Cross-reference any `AuthorizationPolicy` that uses L7 fields (`to.operation.methods`, `to.operation.paths`, `to.operation.hosts`, `when` keys for `request.headers`, `request.auth.claims`) — if no waypoint is bound to the workload, **the L7 rules are accepted by the API server but never enforced**.
|
|
22
|
-
|
|
23
|
-
The L4 fields that ztunnel enforces without a waypoint:
|
|
24
|
-
|
|
25
|
-
- `from.source.principals` (SPIFFE identities — the workload's ServiceAccount mTLS identity)
|
|
26
|
-
- `from.source.namespaces`
|
|
27
|
-
- `to.operation.ports`
|
|
28
|
-
- `when` keys: `source.principal`, `source.namespace`, `destination.port`, `connection.sni`
|
|
29
|
-
|
|
30
|
-
Reference: [L4 Authorization Policy in ambient](https://istio.io/latest/docs/ambient/usage/l4-policy/) and [Waypoint configuration](https://istio.io/latest/docs/ambient/usage/waypoint/).
|
|
31
|
-
|
|
32
|
-
### Step 3 — Audit `PeerAuthentication`
|
|
33
|
-
|
|
34
|
-
`PeerAuthentication` controls workload-to-workload mTLS. Three modes exist with very different security properties:
|
|
35
|
-
|
|
36
|
-
1. **`STRICT`** — all peer connections must use mTLS. Plaintext connections are rejected. Production target.
|
|
37
|
-
2. **`PERMISSIVE`** — accepts both mTLS and plaintext. Useful only during migration.
|
|
38
|
-
3. **`DISABLE`** — disables mTLS. Plaintext only.
|
|
39
|
-
|
|
40
|
-
Stress-tests:
|
|
41
|
-
|
|
42
|
-
- **Mesh-wide PeerAuthentication** lives in the mesh root namespace (default `istio-system`). A change here affects every workload in every namespace simultaneously. Treat as critical-blast-radius.
|
|
43
|
-
- **Namespace-scoped PeerAuthentication** with `mode: PERMISSIVE` in production is a finding — there is no migration in progress; this is technical debt.
|
|
44
|
-
- **Workload-scoped PeerAuthentication** with `mode: DISABLE` for a specific port (e.g., a health-check port) is sometimes legitimate but always requires justification.
|
|
45
|
-
- A namespace with **no `PeerAuthentication`** inherits mesh-wide. If mesh-wide is `PERMISSIVE`, the namespace is also `PERMISSIVE`.
|
|
46
|
-
|
|
47
|
-
Reference: [PeerAuthentication API](https://istio.io/latest/docs/reference/config/security/peer_authentication/).
|
|
48
|
-
|
|
49
|
-
### Step 4 — Audit `AuthorizationPolicy`
|
|
50
|
-
|
|
51
|
-
`AuthorizationPolicy` controls who can talk to whom. Default action when no policy exists is **ALLOW** — there is no implicit deny. Zero-trust requires explicit deny policies or explicit narrow ALLOW policies that combine to leave nothing reachable by default.
|
|
52
|
-
|
|
53
|
-
Three actions: `ALLOW`, `DENY`, `CUSTOM`, `AUDIT`.
|
|
54
|
-
|
|
55
|
-
1. **`DENY` policies are evaluated first**, then `ALLOW`. If multiple match, DENY wins.
|
|
56
|
-
2. **Empty `rules` with `action: DENY`** denies everything — total lockdown.
|
|
57
|
-
3. **`action: ALLOW` with no `from` block** allows from anywhere — only useful for narrowing by `to`.
|
|
58
|
-
4. **`action: ALLOW` with `from.source.principals: ['*']`** is also "anywhere" — no practical narrowing.
|
|
59
|
-
|
|
60
|
-
Stress-tests:
|
|
61
|
-
|
|
62
|
-
- An `AuthorizationPolicy` with `action: ALLOW` and `from.source.namespaces: ['*']` is a documentation-only deny — it allows all and denies none.
|
|
63
|
-
- L7 fields (`to.operation.methods`, `request.auth.claims`) in ambient mode without a waypoint are silently bypassed.
|
|
64
|
-
- `action: AUDIT` is a logging-only mode that does not enforce — use only for migration.
|
|
65
|
-
- Multi-cluster mesh: `AuthorizationPolicy` in one cluster can affect workloads called from another cluster; verify mesh networking topology.
|
|
66
|
-
|
|
67
|
-
Reference: [AuthorizationPolicy API](https://istio.io/latest/docs/reference/config/security/authorization-policy/).
|
|
68
|
-
|
|
69
|
-
### Step 5 — Audit `RequestAuthentication`
|
|
70
|
-
|
|
71
|
-
`RequestAuthentication` defines JWT validation — `jwksUri`, `issuer`, `audiences`, `forwardOriginalToken`. Key concerns:
|
|
72
|
-
|
|
73
|
-
1. **JWKs URI rotation** — if the issuer rotates signing keys, Istio caches the JWKs response. The `jwksUri` URL must remain reachable; outages here cause every JWT to fail.
|
|
74
|
-
2. **`forwardOriginalToken: true`** with sensitive JWTs forwards the bearer token to backend services — they must be trusted.
|
|
75
|
-
3. **`audiences: []` or missing** — accepts JWTs intended for any audience. Cross-service token replay risk.
|
|
76
|
-
4. **Multiple `RequestAuthentication` for the same workload** — Istio combines them. A misconfigured second one can weaken a strict first one.
|
|
77
|
-
|
|
78
|
-
Reference: [RequestAuthentication API](https://istio.io/latest/docs/reference/config/security/request_authentication/).
|
|
79
|
-
|
|
80
|
-
### Step 6 — Audit `Gateway`, `VirtualService`, `DestinationRule`, `Sidecar`
|
|
81
|
-
|
|
82
|
-
Traffic routing concerns:
|
|
83
|
-
|
|
84
|
-
- **`Gateway` with `tls.mode: SIMPLE` and no `credentialName`** — broken or insecure TLS termination.
|
|
85
|
-
- **`Gateway` with `tls.mode: PASSTHROUGH`** plus L7 routing in `VirtualService` — incompatible (passthrough cannot be inspected).
|
|
86
|
-
- **`VirtualService.http.route` with `weight`-based traffic split** — verify total weights sum to 100; otherwise traffic is dropped.
|
|
87
|
-
- **`DestinationRule.trafficPolicy.tls.mode: DISABLE`** on production destinations — disables Istio-side mTLS to the destination.
|
|
88
|
-
- **`Sidecar` resource with `egress.hosts: ['*/*']`** — disables egress restriction.
|
|
89
|
-
|
|
90
|
-
Reference: [Gateway API](https://istio.io/latest/docs/reference/config/networking/gateway/), [VirtualService API](https://istio.io/latest/docs/reference/config/networking/virtual-service/), [DestinationRule API](https://istio.io/latest/docs/reference/config/networking/destination-rule/), [Sidecar API](https://istio.io/latest/docs/reference/config/networking/sidecar/).
|
|
91
|
-
|
|
92
|
-
### Step 7 — Validate with `istioctl analyze`
|
|
93
|
-
|
|
94
|
-
`istioctl analyze` runs the same checks the control plane runs and surfaces structural problems. Run it on the proposed YAML before applying:
|
|
95
|
-
|
|
96
|
-
```shell
|
|
97
|
-
istioctl analyze -n <namespace> # one namespace
|
|
98
|
-
istioctl analyze --all-namespaces # whole mesh
|
|
99
|
-
istioctl analyze --recursive ./manifests/ # offline against files
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Common findings:
|
|
103
|
-
|
|
104
|
-
- `IST0101` — referenced resource not found (e.g., `VirtualService` references a missing host).
|
|
105
|
-
- `IST0118` — port name not following Istio's protocol convention (e.g., `tcp` vs `tcp-mysql`).
|
|
106
|
-
- `IST0127` — namespace not labeled for injection.
|
|
107
|
-
|
|
108
|
-
## Output
|
|
109
|
-
|
|
110
|
-
Return:
|
|
111
|
-
|
|
112
|
-
- **target**: the resource and its scope (mesh-wide, namespace, workload),
|
|
113
|
-
- **evidence level**: `live evidence` / `documentation-based` / `sanitized user evidence` / `inference`,
|
|
114
|
-
- **mesh mode**: sidecar, ambient, or mixed for the affected workloads,
|
|
115
|
-
- **waypoint state**: deployed and bound, missing, or not applicable (sidecar mode),
|
|
116
|
-
- **L7 enforcement assessment**: whether L7 fields will actually run, with explicit "silently ignored" callouts where applicable,
|
|
117
|
-
- **mTLS posture**: `STRICT` / `PERMISSIVE` / `DISABLE` per workload / namespace / mesh,
|
|
118
|
-
- **risk findings** (with severity: high / medium / low),
|
|
119
|
-
- **safest next actions** with sample manifest changes and `istioctl analyze` output,
|
|
120
|
-
- **rollback plan**: how to revert the change without breaking mesh traffic mid-flight,
|
|
121
|
-
- **assumptions and missing facts**.
|
|
122
|
-
|
|
123
|
-
## Security notes
|
|
124
|
-
|
|
125
|
-
- Never recommend `PeerAuthentication` `mode: PERMISSIVE` or `DISABLE` for production without a documented mTLS migration plan with a date.
|
|
126
|
-
- Never recommend a mesh-wide root-namespace policy change without staged rollout (single namespace first, observe, expand).
|
|
127
|
-
- Never recommend disabling waypoint enforcement for an ambient namespace if any L7 `AuthorizationPolicy` exists for that namespace.
|
|
128
|
-
- Do not print Istio root CA private keys or JWKs private keys.
|