@raishin/vanguard-frontier-agentic 3.2.0 → 3.4.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +22 -1
- package/.cursor-plugin/plugin.json +22 -1
- package/.github/plugin/marketplace.json +1 -1
- package/README.md +33 -15
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/AGENT.md +112 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/claude-code.agent.md +111 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/codex.toml +37 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/copilot.agent.md +120 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/cursor.agent.md +112 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/gemini.agent.md +112 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/kiro-ide.agent.md +111 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/metadata.json +42 -0
- package/agents/java/README.md +73 -0
- package/agents/java/java-application-server-exit-agent/AGENT.md +59 -0
- package/agents/java/java-application-server-exit-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-application-server-exit-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-application-server-exit-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/metadata.json +41 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/AGENT.md +59 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/metadata.json +41 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/AGENT.md +59 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/metadata.json +41 -0
- package/agents/java/java-database-migration-safety-agent/AGENT.md +59 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/metadata.json +41 -0
- package/agents/java/java-deserialization-and-parser-security-agent/AGENT.md +57 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/claude-code.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/codex.toml +37 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/copilot.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/cursor.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/gemini.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/kiro-ide.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/metadata.json +41 -0
- package/agents/java/java-framework-production-readiness-agent/AGENT.md +57 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/claude-code.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/codex.toml +39 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/copilot.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/cursor.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/gemini.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/kiro-ide.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/metadata.json +41 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/AGENT.md +55 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/codex.toml +37 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/copilot.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/cursor.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/gemini.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/metadata.json +41 -0
- package/agents/java/java-jpa-hibernate-performance-agent/AGENT.md +57 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/claude-code.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/codex.toml +38 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/copilot.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/cursor.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/gemini.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/kiro-ide.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/metadata.json +41 -0
- package/agents/java/java-jvm-performance-and-gc-agent/AGENT.md +60 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/claude-code.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/copilot.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/cursor.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/gemini.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/kiro-ide.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/metadata.json +41 -0
- package/agents/java/java-kafka-reliability-agent/AGENT.md +60 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/claude-code.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/copilot.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/cursor.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/gemini.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/kiro-ide.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/metadata.json +40 -0
- package/agents/java/java-maestro-agent/AGENT.md +51 -0
- package/agents/java/java-maestro-agent/harnesses/claude-code.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/codex.toml +37 -0
- package/agents/java/java-maestro-agent/harnesses/copilot.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/cursor.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/gemini.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-maestro-agent/harnesses/kiro-ide.agent.md +34 -0
- package/agents/java/java-maestro-agent/metadata.json +40 -0
- package/agents/java/java-resilience-pattern-agent/AGENT.md +59 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/codex.toml +39 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/metadata.json +42 -0
- package/agents/java/java-spring-security-agent/AGENT.md +59 -0
- package/agents/java/java-spring-security-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/codex.toml +39 -0
- package/agents/java/java-spring-security-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-spring-security-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-spring-security-agent/metadata.json +40 -0
- package/agents/java/java-test-architecture-agent/AGENT.md +60 -0
- package/agents/java/java-test-architecture-agent/harnesses/claude-code.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-test-architecture-agent/harnesses/copilot.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/cursor.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/gemini.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-test-architecture-agent/harnesses/kiro-ide.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/metadata.json +42 -0
- package/agents/java/java-transaction-and-consistency-agent/AGENT.md +58 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/claude-code.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/copilot.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/cursor.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/gemini.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/kiro-ide.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/metadata.json +41 -0
- package/agents/php/composer-supply-chain-agent/AGENT.md +114 -0
- package/agents/php/composer-supply-chain-agent/harnesses/claude-code.agent.md +113 -0
- package/agents/php/composer-supply-chain-agent/harnesses/codex.toml +119 -0
- package/agents/php/composer-supply-chain-agent/harnesses/copilot.agent.md +122 -0
- package/agents/php/composer-supply-chain-agent/harnesses/cursor.agent.md +114 -0
- package/agents/php/composer-supply-chain-agent/harnesses/gemini.agent.md +114 -0
- package/agents/php/composer-supply-chain-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/composer-supply-chain-agent/harnesses/kiro-ide.agent.md +113 -0
- package/agents/php/composer-supply-chain-agent/metadata.json +31 -0
- package/agents/php/php-application-security-agent/AGENT.md +113 -0
- package/agents/php/php-application-security-agent/harnesses/claude-code.agent.md +112 -0
- package/agents/php/php-application-security-agent/harnesses/codex.toml +118 -0
- package/agents/php/php-application-security-agent/harnesses/copilot.agent.md +121 -0
- package/agents/php/php-application-security-agent/harnesses/cursor.agent.md +113 -0
- package/agents/php/php-application-security-agent/harnesses/gemini.agent.md +113 -0
- package/agents/php/php-application-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/php-application-security-agent/harnesses/kiro-ide.agent.md +112 -0
- package/agents/php/php-application-security-agent/metadata.json +31 -0
- package/agents/php/php-maestro-agent/AGENT.md +81 -0
- package/agents/php/php-maestro-agent/harnesses/claude-code.agent.md +80 -0
- package/agents/php/php-maestro-agent/harnesses/codex.toml +86 -0
- package/agents/php/php-maestro-agent/harnesses/copilot.agent.md +89 -0
- package/agents/php/php-maestro-agent/harnesses/cursor.agent.md +81 -0
- package/agents/php/php-maestro-agent/harnesses/gemini.agent.md +81 -0
- package/agents/php/php-maestro-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/php-maestro-agent/harnesses/kiro-ide.agent.md +80 -0
- package/agents/php/php-maestro-agent/metadata.json +31 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/AGENT.md +117 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/claude-code.agent.md +116 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/codex.toml +122 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/copilot.agent.md +125 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/cursor.agent.md +117 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/gemini.agent.md +117 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/kiro-ide.agent.md +116 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/metadata.json +30 -0
- package/agents/php/wordpress-security-agent/AGENT.md +107 -0
- package/agents/php/wordpress-security-agent/harnesses/claude-code.agent.md +106 -0
- package/agents/php/wordpress-security-agent/harnesses/codex.toml +112 -0
- package/agents/php/wordpress-security-agent/harnesses/copilot.agent.md +115 -0
- package/agents/php/wordpress-security-agent/harnesses/cursor.agent.md +107 -0
- package/agents/php/wordpress-security-agent/harnesses/gemini.agent.md +107 -0
- package/agents/php/wordpress-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/wordpress-security-agent/harnesses/kiro-ide.agent.md +106 -0
- package/agents/php/wordpress-security-agent/metadata.json +31 -0
- package/catalog/agents.json +609 -0
- package/catalog/asset-integrity.json +1338 -48
- package/catalog/install-roles.json +64 -4
- package/catalog/model-assignments.json +777 -84
- package/catalog/model-policy.json +5 -0
- package/catalog/skill-manifest.json +657 -0
- package/catalog/skills.json +567 -0
- package/package.json +1 -1
- package/plugins/vanguard-frontier-agentic/.codex-plugin/plugin.json +1 -1
- package/powers/README.md +4 -2
- package/powers/vanguard-generic/POWER.md +1 -1
- package/powers/vanguard-java/POWER.md +40 -0
- package/powers/vanguard-php/POWER.md +40 -0
- package/schemas/agent.schema.json +18 -1
- package/schemas/skill.schema.json +27 -1
- package/scripts/generate-docs-data.mjs +1 -1
- package/skills/cross-functional/revenue-critical-journey-integrity-review/SKILL.md +108 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/metadata.json +29 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/idempotency-and-safe-retries.md +155 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/official-sources.md +71 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/pci-saq-scope-boundaries.md +118 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/server-side-revalidation-trust-boundary.md +134 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/webhook-delivery-dedup-ordering.md +146 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/workflow-and-output.md +100 -0
- package/skills/java/java-application-server-exit/SKILL.md +59 -0
- package/skills/java/java-application-server-exit/metadata.json +27 -0
- package/skills/java/java-application-server-exit/references/decision-model-and-cost-inputs.md +60 -0
- package/skills/java/java-application-server-exit/references/vendor-lifecycle-sources.md +52 -0
- package/skills/java/java-application-server-exit/references/workflow-and-output.md +102 -0
- package/skills/java/java-concurrency-and-virtual-thread/SKILL.md +60 -0
- package/skills/java/java-concurrency-and-virtual-thread/metadata.json +27 -0
- package/skills/java/java-concurrency-and-virtual-thread/references/carrier-pinning-and-jdk-version-gating.md +42 -0
- package/skills/java/java-concurrency-and-virtual-thread/references/virtual-thread-lifecycle-and-resource-bounds.md +71 -0
- package/skills/java/java-concurrency-and-virtual-thread/references/workflow-and-output.md +102 -0
- package/skills/java/java-container-and-kubernetes-readiness/SKILL.md +58 -0
- package/skills/java/java-container-and-kubernetes-readiness/metadata.json +27 -0
- package/skills/java/java-container-and-kubernetes-readiness/references/cpu-and-gc-probe-interaction.md +46 -0
- package/skills/java/java-container-and-kubernetes-readiness/references/memory-headroom-and-heap-sizing.md +37 -0
- package/skills/java/java-container-and-kubernetes-readiness/references/workflow-and-output.md +103 -0
- package/skills/java/java-database-migration-safety/SKILL.md +58 -0
- package/skills/java/java-database-migration-safety/metadata.json +27 -0
- package/skills/java/java-database-migration-safety/references/expand-contract-and-destructive-ddl.md +57 -0
- package/skills/java/java-database-migration-safety/references/migration-integrity-and-ordering.md +51 -0
- package/skills/java/java-database-migration-safety/references/workflow-and-output.md +95 -0
- package/skills/java/java-deserialization-and-parser-security/SKILL.md +53 -0
- package/skills/java/java-deserialization-and-parser-security/metadata.json +27 -0
- package/skills/java/java-deserialization-and-parser-security/references/sink-hardening-catalog.md +56 -0
- package/skills/java/java-deserialization-and-parser-security/references/workflow-and-output.md +78 -0
- package/skills/java/java-framework-production-readiness/SKILL.md +59 -0
- package/skills/java/java-framework-production-readiness/metadata.json +27 -0
- package/skills/java/java-framework-production-readiness/references/framework-readiness-checklist.md +78 -0
- package/skills/java/java-framework-production-readiness/references/framework-support-and-eol-boundaries.md +47 -0
- package/skills/java/java-framework-production-readiness/references/workflow-and-output.md +108 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/SKILL.md +54 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/metadata.json +27 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/references/jdk-support-and-license-boundaries.md +61 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/references/lts-migration-and-language-features.md +159 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/references/workflow-and-output.md +101 -0
- package/skills/java/java-jpa-hibernate-performance/SKILL.md +53 -0
- package/skills/java/java-jpa-hibernate-performance/metadata.json +27 -0
- package/skills/java/java-jpa-hibernate-performance/references/fetch-strategy-and-pool-evidence.md +45 -0
- package/skills/java/java-jpa-hibernate-performance/references/workflow-and-output.md +94 -0
- package/skills/java/java-jvm-performance-and-gc/SKILL.md +59 -0
- package/skills/java/java-jvm-performance-and-gc/metadata.json +27 -0
- package/skills/java/java-jvm-performance-and-gc/references/allocation-pressure-and-oom-triage.md +58 -0
- package/skills/java/java-jvm-performance-and-gc/references/collector-selection-and-refusal-contract.md +44 -0
- package/skills/java/java-jvm-performance-and-gc/references/workflow-and-output.md +101 -0
- package/skills/java/java-kafka-reliability/SKILL.md +58 -0
- package/skills/java/java-kafka-reliability/metadata.json +26 -0
- package/skills/java/java-kafka-reliability/references/exactly-once-and-delivery-semantics.md +64 -0
- package/skills/java/java-kafka-reliability/references/ordering-lag-rebalance-and-durability.md +50 -0
- package/skills/java/java-kafka-reliability/references/workflow-and-output.md +107 -0
- package/skills/java/java-maestro/SKILL.md +111 -0
- package/skills/java/java-maestro/metadata.json +26 -0
- package/skills/java/java-resilience-pattern/SKILL.md +60 -0
- package/skills/java/java-resilience-pattern/metadata.json +28 -0
- package/skills/java/java-resilience-pattern/references/aspect-order-and-composition.md +59 -0
- package/skills/java/java-resilience-pattern/references/isolation-and-timeout-budgets.md +57 -0
- package/skills/java/java-resilience-pattern/references/workflow-and-output.md +103 -0
- package/skills/java/java-spring-security/SKILL.md +60 -0
- package/skills/java/java-spring-security/metadata.json +26 -0
- package/skills/java/java-spring-security/references/actuator-endpoint-exposure-catalog.md +45 -0
- package/skills/java/java-spring-security/references/filter-chain-and-authorization-catalog.md +69 -0
- package/skills/java/java-spring-security/references/workflow-and-output.md +79 -0
- package/skills/java/java-test-architecture/SKILL.md +64 -0
- package/skills/java/java-test-architecture/metadata.json +28 -0
- package/skills/java/java-test-architecture/references/junit5-isolation-and-parallelism.md +59 -0
- package/skills/java/java-test-architecture/references/testcontainers-and-archunit-discipline.md +71 -0
- package/skills/java/java-test-architecture/references/workflow-and-output.md +101 -0
- package/skills/java/java-transaction-and-consistency/SKILL.md +60 -0
- package/skills/java/java-transaction-and-consistency/metadata.json +27 -0
- package/skills/java/java-transaction-and-consistency/references/dual-write-outbox-and-saga-patterns.md +125 -0
- package/skills/java/java-transaction-and-consistency/references/propagation-isolation-and-proxy-pitfalls.md +112 -0
- package/skills/java/java-transaction-and-consistency/references/workflow-and-output.md +94 -0
- package/skills/php/composer-audit-supply-chain-review/SKILL.md +108 -0
- package/skills/php/composer-audit-supply-chain-review/metadata.json +20 -0
- package/skills/php/composer-audit-supply-chain-review/references/abandoned-and-advisory-governance.md +30 -0
- package/skills/php/composer-audit-supply-chain-review/references/composer-audit-policy.md +35 -0
- package/skills/php/composer-audit-supply-chain-review/references/lockfile-integrity.md +27 -0
- package/skills/php/php-maestro/SKILL.md +51 -0
- package/skills/php/php-maestro/metadata.json +20 -0
- package/skills/php/php-maestro/references/hard-gates-and-escalation.md +67 -0
- package/skills/php/php-maestro/references/routing-and-dispatch.md +91 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/SKILL.md +109 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/metadata.json +19 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/references/opcache-production-config.md +91 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/references/php-fpm-pool-tuning.md +87 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/references/php-version-lifecycle.md +102 -0
- package/skills/php/php-session-upload-deserialization-review/SKILL.md +111 -0
- package/skills/php/php-session-upload-deserialization-review/metadata.json +20 -0
- package/skills/php/php-session-upload-deserialization-review/references/file-upload-security.md +119 -0
- package/skills/php/php-session-upload-deserialization-review/references/session-security.md +126 -0
- package/skills/php/php-session-upload-deserialization-review/references/unserialize-object-injection.md +121 -0
- package/skills/php/wordpress-rest-block-security-review/SKILL.md +106 -0
- package/skills/php/wordpress-rest-block-security-review/metadata.json +20 -0
- package/skills/php/wordpress-rest-block-security-review/references/dynamic-block-output-escaping.md +42 -0
- package/skills/php/wordpress-rest-block-security-review/references/input-sanitize-output-escape.md +52 -0
- package/skills/php/wordpress-rest-block-security-review/references/rest-api-permission-callback.md +48 -0
- package/tests/fixtures/java-maestro-routing/expected/001-happy-application-server-exit.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/002-happy-concurrency-and-virtual-thread.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/003-happy-container-and-kubernetes-readiness.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/004-happy-database-migration-safety.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/005-happy-deserialization-and-parser-security.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/006-happy-framework-production-readiness.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/007-happy-jdk-lifecycle-and-upgrade.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/008-happy-jpa-hibernate-performance.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/009-happy-jvm-performance-and-gc.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/010-happy-kafka-reliability.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/011-happy-resilience-pattern.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/012-happy-spring-security.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/013-happy-test-architecture.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/014-happy-transaction-and-consistency.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-ambiguous.json +4 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-instruction-injection.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-persona-replacement.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-secrets-bait.json +6 -0
- package/tests/fixtures/java-maestro-routing/inputs/001-happy-application-server-exit.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/002-happy-concurrency-and-virtual-thread.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/003-happy-container-and-kubernetes-readiness.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/004-happy-database-migration-safety.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/005-happy-deserialization-and-parser-security.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/006-happy-framework-production-readiness.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/007-happy-jdk-lifecycle-and-upgrade.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/008-happy-jpa-hibernate-performance.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/009-happy-jvm-performance-and-gc.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/010-happy-kafka-reliability.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/011-happy-resilience-pattern.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/012-happy-spring-security.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/013-happy-test-architecture.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/014-happy-transaction-and-consistency.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-ambiguous.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-instruction-injection.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-persona-replacement.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-secrets-bait.json +7 -0
- package/tests/fixtures/java-maestro-routing/taxonomy.json +177 -0
- package/tests/fixtures/php-maestro-routing/expected/001-happy-application-security.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/002-happy-composer-supply-chain.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/003-happy-runtime-upgrade-readiness.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/004-happy-wordpress-security.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/005-happy-unserialize-session.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/006-happy-fpm-opcache.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/007-happy-composer-audit.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/008-happy-wp-permission-callback.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-ambiguous.json +4 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-instruction-injection.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-liveguard-db-migration-prod.json +4 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-liveguard-deploy-prod.json +4 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-persona-replacement.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-secrets-bait.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/001-happy-application-security.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/002-happy-composer-supply-chain.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/003-happy-runtime-upgrade-readiness.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/004-happy-wordpress-security.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/005-happy-unserialize-session.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/006-happy-fpm-opcache.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/007-happy-composer-audit.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/008-happy-wp-permission-callback.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-ambiguous.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-instruction-injection.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-liveguard-db-migration-prod.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-liveguard-deploy-prod.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-persona-replacement.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-secrets-bait.json +7 -0
- package/tests/fixtures/php-maestro-routing/taxonomy.json +69 -0
- package/tests/validate-catalog.py +2 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "java-transaction-and-consistency",
|
|
3
|
+
"name": "java-transaction-and-consistency",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "skill",
|
|
6
|
+
"provider": "java",
|
|
7
|
+
"harnesses": [
|
|
8
|
+
"codex",
|
|
9
|
+
"claude-code",
|
|
10
|
+
"cursor",
|
|
11
|
+
"gemini",
|
|
12
|
+
"kiro",
|
|
13
|
+
"other"
|
|
14
|
+
],
|
|
15
|
+
"summary": "Statically reviews Spring @Transactional boundary correctness — propagation, isolation, readOnly, rollbackFor, proxy self-invocation, and boundary width — plus cross-resource consistency, flagging the save()-then-send() dual-write anti-pattern, missing outbox/relay, and post-commit side effects that skip TransactionSynchronization or REQUIRES_NEW. Reads source and sanitized configuration only.",
|
|
16
|
+
"source_type": "original",
|
|
17
|
+
"official_docs": [
|
|
18
|
+
"https://docs.spring.io/spring-framework/reference/data-access/transaction.html",
|
|
19
|
+
"https://jakarta.ee/specifications/transactions/",
|
|
20
|
+
"https://microservices.io/patterns/data/transactional-outbox.html",
|
|
21
|
+
"https://microservices.io/patterns/data/saga.html"
|
|
22
|
+
],
|
|
23
|
+
"security_notes": "Static review only — reads Spring @Transactional-annotated classes, service/repository call graphs, and sanitized transaction-manager/datasource/broker configuration; never opens a database or broker connection, starts or commits a transaction, or executes code. Never requests connection strings, credentials, tenant identifiers, or customer data; ask for source with placeholders.",
|
|
24
|
+
"last_verified": "2026-07-17",
|
|
25
|
+
"path": "skills/java/java-transaction-and-consistency",
|
|
26
|
+
"author": "github: Raishin"
|
|
27
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Dual-Write, Outbox, and Saga Patterns
|
|
2
|
+
|
|
3
|
+
> Static review only. Every conclusion below requires the actual write-then-publish (or write-then-call) call site as evidence — a consistency claim without seeing both operations, and whether they share a transaction, is `inference (partial source)` or `assumption (source absent)`. Sources: the transactional outbox and saga patterns as documented on microservices.io (Chris Richardson's pattern catalog, the commonly cited reference for these two patterns); Jakarta Transactions (JTA) specification for the XA/2PC model these patterns exist to avoid at the cross-service level. Broker-specific delivery-semantics details (Kafka's idempotent producer, `transactional.id`, consumer `isolation.level`) are explicitly out of scope here — see the escalation section.
|
|
4
|
+
|
|
5
|
+
## The dual-write problem
|
|
6
|
+
|
|
7
|
+
```java
|
|
8
|
+
@Service
|
|
9
|
+
public class OrderService {
|
|
10
|
+
|
|
11
|
+
@Transactional
|
|
12
|
+
public void placeOrder(Order order) {
|
|
13
|
+
orderRepository.save(order); // resource #1: the database
|
|
14
|
+
eventPublisher.publish( // resource #2: the broker
|
|
15
|
+
new OrderPlacedEvent(order.getId())
|
|
16
|
+
);
|
|
17
|
+
// BAD: these two writes are to two independent resources.
|
|
18
|
+
// The @Transactional boundary only covers the database. If the
|
|
19
|
+
// process crashes, the broker is unreachable, or the publish
|
|
20
|
+
// call throws AFTER the DB transaction has already committed
|
|
21
|
+
// (or even mid-commit, depending on where publish() sits
|
|
22
|
+
// relative to the transaction's actual commit point), the
|
|
23
|
+
// event is silently lost. If publish() is retried on a
|
|
24
|
+
// transient failure after the DB already committed, the event
|
|
25
|
+
// can be silently duplicated instead.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
There is no ordering of `save()` and `publish()` inside a single `@Transactional` method that makes this atomic — a relational database commit and a message-broker publish are two separate resource managers with no shared commit protocol in this design. This holds whether `publish()` runs before or after `save()`, and whether it runs inside or outside the annotated boundary; moving it does not fix the fundamental problem, it only changes which side is more likely to lose the race.
|
|
31
|
+
|
|
32
|
+
## The remedy: transactional outbox
|
|
33
|
+
|
|
34
|
+
```java
|
|
35
|
+
@Service
|
|
36
|
+
public class OrderService {
|
|
37
|
+
|
|
38
|
+
@Transactional
|
|
39
|
+
public void placeOrder(Order order) {
|
|
40
|
+
orderRepository.save(order);
|
|
41
|
+
// GOOD: write the intent to publish into an outbox table, in
|
|
42
|
+
// the SAME database transaction as the order write. Either
|
|
43
|
+
// both rows exist after commit, or neither does — ordinary
|
|
44
|
+
// single-resource ACID, no distributed coordination needed.
|
|
45
|
+
outboxRepository.save(new OutboxEvent(
|
|
46
|
+
"OrderPlaced", order.getId(), toJson(order)
|
|
47
|
+
));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// A SEPARATE process — a polling relay or a CDC-based reader
|
|
52
|
+
// (e.g. reading the outbox table's change stream) — reads unpublished
|
|
53
|
+
// outbox rows and publishes them, marking each processed only after
|
|
54
|
+
// a successful publish acknowledgment. This relay's own delivery
|
|
55
|
+
// guarantees (retry, dedup, ordering) are what actually need
|
|
56
|
+
// verifying — not the original save() call site.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The outbox pattern converts a two-resource atomicity problem into a single-resource one (the DB write of the business row *and* the outbox row happen together, ordinarily) plus a separately-verifiable relay problem (does the relay eventually publish every unprocessed row, and does it avoid publishing the same row twice in a way consumers can't tolerate). Flag a design that writes directly to the broker from the request-handling transaction as needing an outbox; flag an outbox implementation that lacks a described relay (a table that fills up with rows nothing ever reads is not a working outbox).
|
|
60
|
+
|
|
61
|
+
## Post-commit side effects that aren't publish-to-a-broker
|
|
62
|
+
|
|
63
|
+
The same class of bug shows up for any post-commit side effect, not just messaging — calling another service synchronously, invalidating a cache, sending a notification:
|
|
64
|
+
|
|
65
|
+
```java
|
|
66
|
+
@Transactional
|
|
67
|
+
public void approveOrder(Order order) {
|
|
68
|
+
order.setStatus(APPROVED);
|
|
69
|
+
orderRepository.save(order);
|
|
70
|
+
// BAD: if the transaction rolls back after this line runs (e.g. a
|
|
71
|
+
// later step in the same method throws), the notification has
|
|
72
|
+
// already gone out for an approval that never actually committed.
|
|
73
|
+
notificationService.sendApprovalEmail(order);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```java
|
|
78
|
+
@Service
|
|
79
|
+
public class OrderService {
|
|
80
|
+
|
|
81
|
+
@Transactional
|
|
82
|
+
public void approveOrder(Order order) {
|
|
83
|
+
order.setStatus(APPROVED);
|
|
84
|
+
orderRepository.save(order);
|
|
85
|
+
// GOOD: defer the side effect until commit is guaranteed.
|
|
86
|
+
TransactionSynchronizationManager.registerSynchronization(
|
|
87
|
+
new TransactionSynchronization() {
|
|
88
|
+
@Override
|
|
89
|
+
public void afterCommit() {
|
|
90
|
+
notificationService.sendApprovalEmail(order);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Or, declaratively, with an application event:
|
|
98
|
+
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
|
99
|
+
public void onOrderApproved(OrderApprovedEvent event) {
|
|
100
|
+
notificationService.sendApprovalEmail(event.getOrder());
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`registerSynchronization`/`@TransactionalEventListener(phase = AFTER_COMMIT)` only guarantee the callback runs after the *current* transaction manager's commit — they do not make the side effect itself durable or exactly-once. If the process crashes between commit and the callback executing, the side effect is still lost; for a side effect that must survive that gap, it needs the same outbox treatment as messaging, not just an `AFTER_COMMIT` listener. Flag an `AFTER_COMMIT` listener presented as a complete fix for a side effect that must not be lost — it closes the pre-commit race but not the post-commit crash window.
|
|
105
|
+
|
|
106
|
+
## Cross-service atomicity: XA/2PC versus saga
|
|
107
|
+
|
|
108
|
+
A distributed transaction manager (XA, two-phase commit) can, in principle, make a database write and another XA-capable resource commit atomically. Across genuinely independent, separately-deployed services this is usually the wrong tool:
|
|
109
|
+
|
|
110
|
+
- It requires every participant to support and correctly implement the XA protocol — most modern message brokers and NoSQL/managed data stores do not.
|
|
111
|
+
- The coordinator becomes a single point of blocking: participants hold locks (and, for a DB participant, connections) until the coordinator resolves the transaction, which couples the availability of every service to the coordinator and to each other.
|
|
112
|
+
- It does not compose across organizational/deployment boundaries the way a single-service ACID transaction does.
|
|
113
|
+
|
|
114
|
+
The alternative for cross-service consistency is a **saga**: a sequence of local transactions, each in its own service, where every forward step that has an externally-visible effect is paired with a **compensating action** that semantically undoes it if a later step fails. Sagas can be **choreographed** (each service reacts to the previous service's event) or **orchestrated** (a coordinator service explicitly sequences the steps); either way, two properties are non-negotiable:
|
|
115
|
+
|
|
116
|
+
1. **Every forward step's side effect has a compensation.** A step that reserves inventory needs a "release reservation" compensation; a step that charges a card needs a "refund" compensation — not just a log entry saying it should have one.
|
|
117
|
+
2. **Every step (forward and compensating) is idempotent and safe to invoke on a step that never actually ran**, because retries and at-least-once delivery mean a step or its compensation can be invoked more than once, or a compensation can be invoked for a step that failed before doing anything.
|
|
118
|
+
|
|
119
|
+
Flag a design that assumes a distributed transaction manager makes cross-service calls atomic; flag a saga missing a compensation for any forward step with an externally-visible effect; flag a saga whose steps are not clearly idempotent.
|
|
120
|
+
|
|
121
|
+
## Escalation conditions
|
|
122
|
+
|
|
123
|
+
- The finding is really about the broker client's own delivery guarantees — idempotent producer configuration, `transactional.id`, consumer `isolation.level`, offset-commit strategy — rather than whether a dual write exists at all → hand to `java-kafka-reliability-agent`; this agent's job stops at "this needs an outbox / transactional wiring," not designing that wiring.
|
|
124
|
+
- The finding is about `@Transactional` propagation/isolation/rollback on the database side alone, with no second resource involved → see `propagation-isolation-and-proxy-pitfalls.md`; it is not a consistency finding by itself.
|
|
125
|
+
- The user asks to verify actual delivery/exactly-once behavior against a running broker → out of scope for static review; describe what to test and who runs it.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Propagation, Isolation, and Proxy Pitfalls
|
|
2
|
+
|
|
3
|
+
> Static review only. Every conclusion below requires the actual `@Transactional` attributes *and* the call site (who invokes the method, and from where) as evidence — a propagation or rollback claim without both is `inference (partial source)` or `assumption (source absent)`. Sources: Spring Framework Reference — Data Access / Transaction Management (declarative transaction management, propagation, and rollback rules); Jakarta Transactions (JTA) specification for the underlying resource-transaction model Spring's `PlatformTransactionManager` abstracts over. Spring's default propagation and rollback behavior has been stable across recent Spring Framework major lines, but always confirm annotation defaults against the specific Spring Framework version in use before treating a version-specific detail as settled — this reference does not hardcode a version number.
|
|
4
|
+
|
|
5
|
+
## Why propagation is the first thing to check
|
|
6
|
+
|
|
7
|
+
`@Transactional` attributes on a method only fully apply when that method actually **starts** the transaction. Spring's declarative transaction management is proxy-based: it wraps the bean in an AOP proxy that opens/joins/suspends a transaction *before* the target method runs, and commits/rolls back *after* it returns. Everything below follows from that one mechanical fact.
|
|
8
|
+
|
|
9
|
+
## Propagation semantics that get silently overridden
|
|
10
|
+
|
|
11
|
+
| Propagation | Behavior when called with no existing transaction | Behavior when called from within an existing transaction |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `REQUIRED` (default) | Starts a new transaction | **Joins** the caller's transaction — the method's own `isolation`/`timeout` are silently ignored; `readOnly` is honored only if the caller also declared it |
|
|
14
|
+
| `REQUIRES_NEW` | Starts a new transaction | **Suspends** the caller's transaction, runs in a brand-new one, then resumes the caller's — the inner transaction can commit independently of the outer |
|
|
15
|
+
| `MANDATORY` | Throws `IllegalTransactionStateException` | Joins the caller's transaction |
|
|
16
|
+
| `SUPPORTS` | Runs non-transactionally | Joins the caller's transaction |
|
|
17
|
+
| `NOT_SUPPORTED` | Runs non-transactionally | Suspends the caller's transaction and runs non-transactionally |
|
|
18
|
+
| `NEVER` | Runs non-transactionally | Throws `IllegalTransactionStateException` |
|
|
19
|
+
| `NESTED` | Starts a new transaction | Starts a nested transaction using a savepoint (JDBC `RESOURCE_LOCAL` only; not all `PlatformTransactionManager` implementations support it) |
|
|
20
|
+
|
|
21
|
+
**The finding that matters most:** a `REQUIRED` method that declares `isolation = SERIALIZABLE`, `timeout = 5`, or similar, and is *also* called from another `@Transactional` method elsewhere in the codebase, will silently run at whatever isolation/timeout the outer transaction already established. If the call graph shows this method invoked both standalone and from inside another transaction, the inner attributes are unreliable by construction — flag it, don't just check the annotation in isolation.
|
|
22
|
+
|
|
23
|
+
`REQUIRES_NEW` avoids that problem but introduces a different one: the inner transaction can commit even if the outer later rolls back. That is sometimes exactly what's wanted (e.g., an audit-log write that must survive the caller's rollback) and sometimes a bug (a "just to be safe" `REQUIRES_NEW` that breaks atomicity the caller assumed). The evidence needed to tell them apart is *why* the isolation was chosen — ask if it isn't stated.
|
|
24
|
+
|
|
25
|
+
## Proxy self-invocation: the classic silent bypass
|
|
26
|
+
|
|
27
|
+
```java
|
|
28
|
+
@Service
|
|
29
|
+
public class OrderService {
|
|
30
|
+
|
|
31
|
+
public void placeOrder(Order order) {
|
|
32
|
+
// BAD: calling another @Transactional method on `this` goes
|
|
33
|
+
// straight to the method body — it never passes through the
|
|
34
|
+
// Spring-generated proxy, so @Transactional on saveOrder() below
|
|
35
|
+
// is a complete no-op here: no transaction is started, no
|
|
36
|
+
// rollback rule applies, no propagation semantics fire.
|
|
37
|
+
this.saveOrder(order);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@Transactional
|
|
41
|
+
public void saveOrder(Order order) {
|
|
42
|
+
repository.save(order);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This happens because Spring's default AOP is proxy-based (JDK dynamic proxies for interfaces, CGLIB subclassing for concrete classes): the proxy only intercepts calls that arrive from *outside* the bean. A call from one method to another on the same instance (`this.method()`, or simply calling a sibling method by its plain name) never goes through the proxy.
|
|
48
|
+
|
|
49
|
+
Correct alternatives, in order of preference for most codebases:
|
|
50
|
+
|
|
51
|
+
```java
|
|
52
|
+
@Service
|
|
53
|
+
public class OrderService {
|
|
54
|
+
|
|
55
|
+
// 1) Split the transactional method into a separate bean and
|
|
56
|
+
// inject it — the cleanest fix, no proxy tricks required.
|
|
57
|
+
private final OrderWriter orderWriter;
|
|
58
|
+
|
|
59
|
+
public void placeOrder(Order order) {
|
|
60
|
+
orderWriter.saveOrder(order); // goes through orderWriter's proxy
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Component
|
|
65
|
+
class OrderWriter {
|
|
66
|
+
@Transactional
|
|
67
|
+
void saveOrder(Order order) { repository.save(order); }
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Self-injection (`@Autowired private OrderService self;` then `self.saveOrder(order)`) or `AopContext.currentProxy()` (requires `exposeProxy = true` on the `@EnableAspectJAutoProxy`) both work but are easy to regress if a later edit reverts to `this.`; extraction to a separate bean is the more durable fix. Flag self-invocation regardless of which fix the codebase already uses elsewhere — check every `@Transactional` call site, not just the constructor-injected ones.
|
|
72
|
+
|
|
73
|
+
## rollbackFor: checked exceptions do not roll back by default
|
|
74
|
+
|
|
75
|
+
```java
|
|
76
|
+
@Transactional // BAD if InventoryException is checked and unhandled here
|
|
77
|
+
public void reserveStock(Order order) throws InventoryException {
|
|
78
|
+
inventory.decrement(order.getSku(), order.getQty()); // throws checked InventoryException
|
|
79
|
+
ledger.record(order); // never runs if the exception above propagates —
|
|
80
|
+
// but the transaction still COMMITS on the way out
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Spring's default rollback rule is: roll back on unchecked `RuntimeException` and `Error`; **commit** on a checked exception unless told otherwise. This is the exact inverse of what most developers expect from "an exception happened, surely it rolled back." The fix is explicit:
|
|
85
|
+
|
|
86
|
+
```java
|
|
87
|
+
@Transactional(rollbackFor = InventoryException.class)
|
|
88
|
+
public void reserveStock(Order order) throws InventoryException { ... }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Flag every checked exception declared or thrown from a `@Transactional` method that lacks a matching `rollbackFor` (or a global convention enforced elsewhere, such as wrapping checked exceptions in an unchecked wrapper before they leave the method — verify that convention actually holds at the site under review rather than assuming it).
|
|
92
|
+
|
|
93
|
+
## readOnly: an optimization hint, not just documentation
|
|
94
|
+
|
|
95
|
+
`readOnly = true` is a hint to the underlying resource: Hibernate can skip dirty-checking/flush, and some `DataSource`/driver/pool combinations route read-only connections differently (e.g., to a read replica, or reject a write outright). **This behavior is infrastructure-dependent** — Spring and JPA do not guarantee a specific outcome for a write inside a `readOnly = true` transaction; it can silently no-op, silently succeed, or throw, depending on the driver and pool configuration in use. Treat a write inside a `readOnly = true` method as a defect regardless of which of those three outcomes the current stack happens to produce, and mark the exact runtime consequence as `unknown` unless the driver/pool configuration was provided.
|
|
96
|
+
|
|
97
|
+
## Isolation levels: name the anomaly, and mind vendor differences
|
|
98
|
+
|
|
99
|
+
| Level | Prevents |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `READ_UNCOMMITTED` | Nothing extra beyond `DEFAULT`'s DB baseline |
|
|
102
|
+
| `READ_COMMITTED` | Dirty reads |
|
|
103
|
+
| `REPEATABLE_READ` | Dirty reads, non-repeatable reads |
|
|
104
|
+
| `SERIALIZABLE` | Dirty reads, non-repeatable reads, phantom reads |
|
|
105
|
+
|
|
106
|
+
Treat this table as the *conceptual* SQL-standard mapping, not a promise about every database's actual implementation: some vendors alias `READ_UNCOMMITTED` up to `READ_COMMITTED`, and `REPEATABLE_READ`/`SERIALIZABLE` are implemented differently across engines (locking vs. MVCC/snapshot). Without knowing the target database and version, treat any claim about which specific anomaly a chosen isolation level prevents *on that database* as `inference (partial source)` at best.
|
|
107
|
+
|
|
108
|
+
## Escalation conditions
|
|
109
|
+
|
|
110
|
+
- The consistency question is really about a broker's producer/consumer transactional configuration (idempotent producer, `transactional.id`, `isolation.level`) rather than the application's transaction boundary → hand to `java-kafka-reliability-agent`.
|
|
111
|
+
- The slow-query or N+1 symptom sits inside a correctly-bounded transaction → hand to `java-jpa-hibernate-performance-agent`; boundary correctness and query shape are separate defects.
|
|
112
|
+
- The user asks to actually run the code to observe commit/rollback behavior → out of scope for static review; describe what to instrument and who runs it.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Workflow and Output Contract
|
|
2
|
+
|
|
3
|
+
> Static review only. Read `@Transactional`-annotated classes, their call graph, and sanitized configuration (transaction-manager beans, datasource pool settings, broker client config only insofar as it evidences a dual write). Never open a database or broker connection, start or commit a transaction, or execute code. Ask for source with placeholders — never connection strings, credentials, tenant identifiers, or customer data.
|
|
4
|
+
|
|
5
|
+
## Workflow
|
|
6
|
+
|
|
7
|
+
### Step 1 — Collect inputs
|
|
8
|
+
|
|
9
|
+
Ask the user for whichever apply, sanitized:
|
|
10
|
+
- The `@Transactional`-annotated method(s) under review, with their full attribute list (`propagation`, `isolation`, `readOnly`, `rollbackFor`/`noRollbackFor`, `timeout`).
|
|
11
|
+
- The call graph: who invokes each `@Transactional` method, and from where (same class/bean vs. a different bean; inside an existing transaction vs. not).
|
|
12
|
+
- Any sequence where a database write is followed by a message/event publish, a call to another service, or a cache update.
|
|
13
|
+
- Any post-commit side-effect handling already in place (`TransactionSynchronization`, `@TransactionalEventListener`, an outbox table, a saga orchestrator/choreography).
|
|
14
|
+
- Relevant configuration: the `PlatformTransactionManager`/datasource bean setup, connection-pool settings if boundary width is in scope, and whether an outbox/relay or saga infrastructure already exists.
|
|
15
|
+
|
|
16
|
+
If the call site or the annotation attributes are missing for a method under discussion, downgrade that finding to `inference (partial source)` or `assumption (source absent)` and say so.
|
|
17
|
+
|
|
18
|
+
### Step 2 — Map propagation and rollback per method
|
|
19
|
+
|
|
20
|
+
For each `@Transactional` method, record: propagation, isolation, readOnly, rollbackFor/noRollbackFor, and every checked exception it declares or can throw. Cross-reference against the default rollback rule (unchecked + `Error` only) to find gaps.
|
|
21
|
+
|
|
22
|
+
### Step 3 — Trace every call site for self-invocation and join behavior
|
|
23
|
+
|
|
24
|
+
For each `@Transactional` method, determine: is it ever called from another method on the *same* bean (self-invocation — flag unconditionally)? Is it ever called from within another `@Transactional` method elsewhere (a `REQUIRED` join — its own isolation/timeout are then unreliable)? Is its boundary width limited to DB work, or does it wrap an external call?
|
|
25
|
+
|
|
26
|
+
### Step 4 — Detect dual-write and post-commit races
|
|
27
|
+
|
|
28
|
+
For each sequence that writes to the database and then touches a second resource (broker, service call, cache): is the second write inside the same DB transaction (it can't truly be — flag if the code implies otherwise), deferred to `AFTER_COMMIT`, or routed through an outbox? A direct publish/call with no outbox and no `AFTER_COMMIT` deferral is the dual-write anti-pattern regardless of ordering.
|
|
29
|
+
|
|
30
|
+
### Step 5 — Assess cross-service consistency design
|
|
31
|
+
|
|
32
|
+
If the consistency question spans services: is atomicity attempted via a distributed transaction manager (flag as fragile) or a saga? If a saga, does every forward step with an externally visible effect have a paired, idempotent compensation, and are steps idempotent under retry?
|
|
33
|
+
|
|
34
|
+
### Step 6 — Produce the output
|
|
35
|
+
|
|
36
|
+
Format using the Output contract below. Pick each remedy by the actual resources and call graph involved; never recommend a manual pseudo-outbox, a blanket `REQUIRES_NEW` everywhere, or XA/2PC across service boundaries as a default.
|
|
37
|
+
|
|
38
|
+
## Evidence checklist
|
|
39
|
+
|
|
40
|
+
- [ ] `@Transactional` attributes for each method in scope
|
|
41
|
+
- [ ] Call graph (same-bean self-invocation and cross-transaction joins)
|
|
42
|
+
- [ ] Any write-then-publish/call/cache sequence and its resource boundaries
|
|
43
|
+
- [ ] Existing post-commit handling (`AFTER_COMMIT`, outbox, saga infrastructure)
|
|
44
|
+
- [ ] Transaction-manager and pool configuration (if boundary width is in scope)
|
|
45
|
+
|
|
46
|
+
Each unchecked item downgrades the related findings to `inference` or `assumption`.
|
|
47
|
+
|
|
48
|
+
## Findings rubric
|
|
49
|
+
|
|
50
|
+
| Severity | Criteria |
|
|
51
|
+
|----------|----------|
|
|
52
|
+
| critical | Proxy self-invocation silently skipping `@Transactional`; checked exception with no `rollbackFor` committing a failed write; save()-then-send() dual write with no outbox; a required isolation/timeout silently dropped under a `REQUIRED` join with a stated correctness dependency on it. |
|
|
53
|
+
| high | Over-wide boundary wrapping an external call; post-commit side effect not deferred to `AFTER_COMMIT`/outbox; `readOnly = true` performing a write; cross-service atomicity attempted via XA/2PC. |
|
|
54
|
+
| medium | Unjustified relaxed isolation level; `REQUIRES_NEW` used without stating the commit-independence trade-off; incomplete saga compensation coverage. |
|
|
55
|
+
| low | Large batch operation in one long-lived transaction; a genuinely read-only method missing `readOnly = true`. |
|
|
56
|
+
|
|
57
|
+
Every finding carries an evidence-basis label: `confirmed (source provided)`, `inference (partial source)`, `assumption (source absent)`, or `unknown`.
|
|
58
|
+
|
|
59
|
+
## Output contract
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
## Verdict
|
|
63
|
+
<pass | pass-with-conditions | block>
|
|
64
|
+
|
|
65
|
+
## Evidence level
|
|
66
|
+
<full source | partial source | inference>
|
|
67
|
+
|
|
68
|
+
## Findings
|
|
69
|
+
|
|
70
|
+
### CRITICAL
|
|
71
|
+
- [C1] <finding> — <evidence basis> — <call site / resource pair> — <remedy: rollbackFor / de-duplicate self-invocation / outbox / AFTER_COMMIT>
|
|
72
|
+
|
|
73
|
+
### HIGH
|
|
74
|
+
- [H1] <finding> — <evidence basis> — <description> — <remediation>
|
|
75
|
+
|
|
76
|
+
### MEDIUM
|
|
77
|
+
- [M1] <finding> — <evidence basis> — <description> — <remediation>
|
|
78
|
+
|
|
79
|
+
### LOW
|
|
80
|
+
- [L1] <finding> — <evidence basis> — <description> — <remediation>
|
|
81
|
+
|
|
82
|
+
## Safe next actions
|
|
83
|
+
1. <action>
|
|
84
|
+
|
|
85
|
+
## Open questions
|
|
86
|
+
- <annotation attribute, call site, or resource boundary the user must supply>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Security notes
|
|
90
|
+
|
|
91
|
+
- Never request or accept connection strings, credentials, tenant identifiers, or customer data. Ask for source with placeholders.
|
|
92
|
+
- Static review only: never open a database or broker connection, start or commit a transaction, or execute code.
|
|
93
|
+
- Never recommend a manual pseudo-two-phase workaround, a blanket `REQUIRES_NEW`, or XA/2PC across service boundaries as a default fix.
|
|
94
|
+
- Never recommend disabling a failing gate as the fix.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: composer-audit-supply-chain-review
|
|
3
|
+
description: Use this skill to review PHP Composer dependency supply-chain posture — whether composer audit is wired into CI with a failing exit-code gate on security advisories, whether config.policy.advisories.audit and config.policy.abandoned settings are configured to actually surface risk, whether abandoned packages have a tracked replacement plan, and whether composer.lock is present, current, and pins dependencies at security-sensitive boundaries. Use when a vulnerable or abandoned Packagist dependency could reach production because the audit gate is missing or non-blocking, an abandoned package has no owner, or the lock file is absent, drifted, or bypassed by unpinned constraints. Static review only; it never installs packages, runs Composer commands, or contacts Packagist.
|
|
4
|
+
allowed-tools: Read Grep Glob
|
|
5
|
+
metadata:
|
|
6
|
+
author: "github: Raishin"
|
|
7
|
+
version: "0.1.0"
|
|
8
|
+
updated: "2026-07-16"
|
|
9
|
+
category: security
|
|
10
|
+
lifecycle: experimental
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Composer Audit & Supply-Chain Review
|
|
14
|
+
|
|
15
|
+
## Purpose
|
|
16
|
+
|
|
17
|
+
Review a PHP project's Composer dependency supply chain so a vulnerable or abandoned Packagist package cannot reach production unnoticed. The dominant failure modes are `composer audit` missing from CI (or present but not gating on its exit code), advisory/abandoned policy configured to report instead of fail, abandoned packages with no tracked replacement, and `composer.lock` that is absent, drifted, or undermined by unpinned dependency constraints at security-sensitive boundaries.
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
Use this skill when the user asks to:
|
|
22
|
+
|
|
23
|
+
- review whether `composer audit` actually gates CI on security advisories, rather than merely running and being ignored,
|
|
24
|
+
- review `config.policy.advisories.audit` / `config.policy.abandoned.audit` / `config.policy.abandoned.block` settings for a PHP project,
|
|
25
|
+
- assess abandoned Packagist dependencies for replacement-plan coverage,
|
|
26
|
+
- review whether `composer.lock` is present, current, and consistent with `composer.json`,
|
|
27
|
+
- review dependency pinning at security-sensitive boundaries (auth, crypto, serialization, payment) for unpinned or overly wide version constraints.
|
|
28
|
+
|
|
29
|
+
## When not to use
|
|
30
|
+
|
|
31
|
+
Do not use this skill for:
|
|
32
|
+
|
|
33
|
+
- installing, updating, or removing packages, or running `composer install`/`update`/`audit` against any live, sandbox, or CI environment — this skill is static review only.
|
|
34
|
+
- application architecture or dependency-injection redesign, or choosing a specific replacement package on the team's behalf — name the risk and hand the decision to the owning engineer.
|
|
35
|
+
- reviewing non-Composer package ecosystems (npm, pip, RubyGems, etc.) — this skill is Composer/Packagist-specific.
|
|
36
|
+
- asserting a specific deployment is free of vulnerable dependencies from configuration review alone; a clean-looking policy does not prove the last audit run was clean.
|
|
37
|
+
|
|
38
|
+
## Preconditions
|
|
39
|
+
|
|
40
|
+
- `composer.json` (including any `config.policy` block) and `composer.lock`, if one exists, for the project in scope.
|
|
41
|
+
- The CI pipeline definition(s) that build, test, or deploy the project, to confirm whether `composer audit` runs and whether its exit code gates the pipeline.
|
|
42
|
+
- Any existing `composer audit` output, report, or CI log excerpt available for the repository.
|
|
43
|
+
- The Composer version in use or its constraint, since `config.policy.abandoned.audit` defaults differ between Composer 2.6 (`report`) and Composer 2.7+ (`fail`).
|
|
44
|
+
- Any documented accepted-risk exceptions for specific advisories or abandoned packages, if the team maintains them.
|
|
45
|
+
|
|
46
|
+
## Lean operating rules
|
|
47
|
+
|
|
48
|
+
- Confirm `composer audit` is both present in CI and gating — its non-zero exit code must actually fail the job, not be discarded or logged past.
|
|
49
|
+
- Read `config.policy.advisories.audit` and the `config.policy.abandoned.*` keys from `composer.json`; where a key is unset, apply the documented default for the project's Composer version rather than assuming a value.
|
|
50
|
+
- Treat `composer.lock` absence for an application as a blocking finding on its own; the documented exception is that a library is not required to commit its lock file.
|
|
51
|
+
- Treat `composer.lock` drift from `composer.json` (stale-lock warnings, hash mismatches) as a distinct finding from lock absence.
|
|
52
|
+
- Flag unpinned or overly wide version constraints at security-sensitive boundaries even when a lock file exists, since the next `composer update` can still move far without review.
|
|
53
|
+
- Never fabricate an advisory ID, CVE number, or package name; report a gap in evidence rather than inventing an identifier.
|
|
54
|
+
- Label every claim `repo evidence`, `documentation-based`, or `inference`.
|
|
55
|
+
|
|
56
|
+
## Context7 documentation protocol
|
|
57
|
+
|
|
58
|
+
This skill's allowed tools are Read, Grep, and Glob only — it does not call Context7 or any live documentation lookup at review time. Every Composer-specific behavioral claim (exit codes, `config.policy` key names and defaults, lockfile semantics) must instead be grounded in the bundled reference files, which are sourced from the official Composer documentation and dated at authoring time. If a claim cannot be traced to a bundled reference or to evidence in the repository, label it an assumption rather than asserting it as documented behavior. See [official sources](references/composer-audit-policy.md), [abandoned-and-advisory governance](references/abandoned-and-advisory-governance.md), and [lockfile integrity](references/lockfile-integrity.md).
|
|
59
|
+
|
|
60
|
+
## Workflow
|
|
61
|
+
|
|
62
|
+
Follow the review in this order: (1) locate every CI job that builds, tests, or deploys the project and check for a `composer audit` step; (2) confirm that step's exit code is not suppressed (no `|| true`, no `continue-on-error`, no output-only reporting); (3) read `config.policy.advisories.audit` and the `config.policy.abandoned.*` keys, comparing against documented defaults for the Composer version in use; (4) check for abandoned packages already flagged in any available audit output or lockfile metadata, and whether a replacement plan or accepted-risk exception exists; (5) confirm `composer.lock` is present and check for drift against `composer.json`; (6) scan dependency constraints for unpinned or overly wide ranges at security-sensitive boundaries; (7) emit findings with evidence tiers, concrete remediation, and ownership handoffs.
|
|
63
|
+
|
|
64
|
+
## Decision gates
|
|
65
|
+
|
|
66
|
+
- Block only when `composer audit` is not run in CI with a failing exit-code gate on advisories, when an abandoned package has no replacement plan, or when `composer.lock` is absent, drifted, or dependencies are floated unpinned at a security-sensitive boundary.
|
|
67
|
+
- Every Composer-specific claim traces to a bundled reference file or explicit repository evidence, never memory.
|
|
68
|
+
- No advisory ID, CVE, or package name is asserted without repository evidence backing it.
|
|
69
|
+
- Application architecture and replacement-package selection are handed to the owning engineer, never decided here.
|
|
70
|
+
|
|
71
|
+
## Evidence classification
|
|
72
|
+
|
|
73
|
+
Label each finding `repo evidence` (seen directly in `composer.json`, `composer.lock`, or CI configuration), `documentation-based` (a Composer-documented default or behavior from the bundled references), or `inference` (a reasonable conclusion not directly observed). A documented default never proves what a specific project's configuration actually is — check the file before asserting the default applies.
|
|
74
|
+
|
|
75
|
+
## Security and privacy constraints
|
|
76
|
+
|
|
77
|
+
Static review only. Never install packages, run `composer install`/`update`/`audit`, or make any network call to Packagist or any registry. Never fabricate advisory IDs, CVE numbers, or package names — report missing evidence instead. Treat any credential found in `auth.json` or Composer configuration as a redact-and-flag finding, never echoed in output.
|
|
78
|
+
|
|
79
|
+
## Escalation conditions
|
|
80
|
+
|
|
81
|
+
Escalate to incident response on any evidence a known-vulnerable or already-flagged-abandoned dependency is already reachable from a production deployment path (e.g. a deployment manifest pinning a version an existing audit output already flags). Escalate abandoned-package findings with no owner to the responsible engineering team as a tracked risk item rather than a routine comment.
|
|
82
|
+
|
|
83
|
+
## References
|
|
84
|
+
|
|
85
|
+
Load these only when needed:
|
|
86
|
+
|
|
87
|
+
- [Composer audit policy](references/composer-audit-policy.md) — `composer audit` behavior, exit codes, and `config.policy.advisories.audit` gating.
|
|
88
|
+
- [Abandoned and advisory governance](references/abandoned-and-advisory-governance.md) — `config.policy.abandoned.audit`/`config.policy.abandoned.block` and replacement-plan review criteria, with OSS-risk context.
|
|
89
|
+
- [Lockfile integrity](references/lockfile-integrity.md) — `composer.lock` presence, drift, and dependency-pinning review criteria.
|
|
90
|
+
|
|
91
|
+
## Response minimum
|
|
92
|
+
|
|
93
|
+
Return, at minimum:
|
|
94
|
+
|
|
95
|
+
- the CI audit-gating state (present and failing / present but non-gating / absent), labeled with evidence tier;
|
|
96
|
+
- the `config.policy.advisories.audit` and `config.policy.abandoned.*` configuration state, compared against documented defaults for the Composer version in use;
|
|
97
|
+
- abandoned-package findings with replacement-plan status;
|
|
98
|
+
- `composer.lock` presence/freshness state and any unpinned-constraint exposure at security-sensitive boundaries;
|
|
99
|
+
- concrete remediation and an exact verification step for each finding;
|
|
100
|
+
- ownership handoffs and any incident-response escalation.
|
|
101
|
+
|
|
102
|
+
## Anti-goals
|
|
103
|
+
|
|
104
|
+
- Do not install packages, run any Composer command, or contact Packagist or any registry.
|
|
105
|
+
- Do not fabricate advisory IDs, CVE numbers, or package names not present in repository evidence.
|
|
106
|
+
- Do not redesign application architecture or select a replacement package on the team's behalf.
|
|
107
|
+
- Do not present the general OSS-risk statistics used as motivation as a finding specific to the repository under review.
|
|
108
|
+
- Do not assert a Composer behavior from memory when it is not grounded in a bundled reference or repository evidence.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "composer-audit-supply-chain-review",
|
|
3
|
+
"name": "Composer Audit & Supply-Chain Review",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"provider": "php",
|
|
6
|
+
"harnesses": ["claude-code", "cursor", "codex", "gemini", "kiro", "other"],
|
|
7
|
+
"summary": "Skill for reviewing Composer dependency supply-chain posture: composer audit advisory scanning and CI exit-code gating, config.policy advisory/abandoned settings, and composer.lock integrity and drift, so a vulnerable or abandoned Packagist dependency cannot reach production ungated.",
|
|
8
|
+
"source_type": "original",
|
|
9
|
+
"official_docs": [
|
|
10
|
+
"https://getcomposer.org/doc/03-cli.md",
|
|
11
|
+
"https://getcomposer.org/doc/06-config.md",
|
|
12
|
+
"https://getcomposer.org/doc/01-basic-usage.md",
|
|
13
|
+
"https://owasp.org/www-project-top-ten/"
|
|
14
|
+
],
|
|
15
|
+
"security_notes": "Static-review-only skill: Read/Grep/Glob, no execution and no network mutation. Never installs, updates, or requires packages. Reports composer audit posture from configuration and lockfile evidence, never fabricates advisory identifiers, and treats any credential in auth.json or configuration as a redact-and-flag finding.",
|
|
16
|
+
"last_verified": "2026-07-16",
|
|
17
|
+
"path": "skills/php/composer-audit-supply-chain-review",
|
|
18
|
+
"author": "github: Raishin",
|
|
19
|
+
"version": "0.1.0"
|
|
20
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Abandoned and Advisory Governance
|
|
2
|
+
|
|
3
|
+
## Why this matters
|
|
4
|
+
|
|
5
|
+
An abandoned Packagist package is not necessarily vulnerable today, but it will not receive a fix if a vulnerability is found tomorrow, and it will not receive a fix now for anything already discovered. Composer can be configured to surface this risk (or block it outright), but the defaults have changed across versions, and a project pinned to an older Composer release may be relying on weaker default behavior than its authors expect. This reference exists so a reviewer checks the actual configured (or defaulted) behavior rather than assuming abandonment is handled.
|
|
6
|
+
|
|
7
|
+
## NORMATIVE facts
|
|
8
|
+
|
|
9
|
+
- `config.policy.abandoned.audit` controls whether and how `composer audit` reports abandoned packages. Allowed values are `ignore`, `report`, and `fail`, matching the same semantics as the advisories policy: `ignore` does not report, `report` reports without a non-zero exit code, and `fail` causes a non-zero exit code. This setting applies only to audit reporting, not to whether abandoned packages can be installed or updated.
|
|
10
|
+
- The default for `config.policy.abandoned.audit` became `fail` in Composer 2.7; it defaulted to `report` in Composer 2.6. A project's Composer version constraint therefore determines which default behavior actually applies unless the key is explicitly set.
|
|
11
|
+
- `config.policy.abandoned.block` is a separate key that, when enabled, prevents abandoned packages from being installed during `update`, `require`, or `remove` operations. Its default value is `false` — meaning by default, Composer does not stop an abandoned package from being installed or updated, it can only be flagged during an audit.
|
|
12
|
+
|
|
13
|
+
## Reviewer evidence criteria
|
|
14
|
+
|
|
15
|
+
- Read `config.policy.abandoned.audit` and `config.policy.abandoned.block` directly from `composer.json`. Do not assume a default without first confirming the key is genuinely unset.
|
|
16
|
+
- If `config.policy.abandoned.audit` is unset, determine the project's Composer version constraint (from `composer.json` `require.composer` or lockfile metadata, if present) to establish which default (`report` for 2.6, `fail` for 2.7+) actually applies, and flag the ambiguity if the version constraint is broad enough to span both.
|
|
17
|
+
- Treat `config.policy.abandoned.block` left at its default `false` as expected baseline behavior, not itself a finding — but combine it with the next check: search for evidence of abandoned packages already present (audit output, lockfile package names cross-referenced against known-abandoned status if such evidence is provided) and confirm each has a tracked replacement plan (a migration ticket, a comment, or documented accepted-risk exception). An abandoned package with no replacement plan and no compensating audit-gating configuration is a blocking finding.
|
|
18
|
+
- Never fabricate a package's abandoned status. Only report a package as abandoned when the repository provides direct evidence (an audit run's output, a Composer warning captured in a log, or an explicit note in project documentation) — a reviewer without that evidence should report the gap ("abandonment status could not be confirmed from available evidence") rather than guessing.
|
|
19
|
+
- When a replacement plan does exist, verify it names a concrete path (a specific replacement package, a scheduled removal, or an accepted-risk sign-off with an expiry or review date) rather than an open-ended "we know about it."
|
|
20
|
+
|
|
21
|
+
## Context: general OSS risk (report figure only)
|
|
22
|
+
|
|
23
|
+
Black Duck's Open Source Security and Risk Analysis (OSSRA) report, published February 25, 2025, found that 86% of commercial codebases evaluated contained open source software vulnerabilities, and 90% of audited codebases had open source components more than four years out of date. This is population-level report context motivating why abandoned and unpatched dependencies deserve deliberate governance — it is never evidence about the specific repository under review, and must not be cited as a finding about this codebase.
|
|
24
|
+
|
|
25
|
+
## Sources
|
|
26
|
+
|
|
27
|
+
- `config.policy.abandoned.audit` and `config.policy.abandoned.block` keys, allowed values, and version-dependent defaults: [Composer config documentation](https://getcomposer.org/doc/06-config.md).
|
|
28
|
+
- General OSS-risk context (86% vulnerable codebases, 90% components 4+ years out of date), cited as report-figure motivation only: [Black Duck 2025 OSSRA report announcement](https://news.blackduck.com/2025-02-25-New-Black-Duck-Report-86-of-Commercial-Codebases-Contain-Vulnerable-Open-Source,-Exposing-Organizations-to-Security-Risks).
|
|
29
|
+
|
|
30
|
+
Last verified: 2026-07-16
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Composer Audit Policy
|
|
2
|
+
|
|
3
|
+
## Why this matters
|
|
4
|
+
|
|
5
|
+
`composer audit` is the built-in mechanism for catching known-vulnerable, abandoned, or malware-flagged dependencies before they ship. A repository can have this command available and still ship a vulnerable dependency to production if the command is never invoked in CI, or if it runs but its result is not allowed to fail the build. The review criteria below exist to catch exactly that gap — a policy that exists on paper but is not actually enforced.
|
|
6
|
+
|
|
7
|
+
## NORMATIVE facts
|
|
8
|
+
|
|
9
|
+
- `composer audit` checks installed packages against known security advisories, abandoned status, and malware flags.
|
|
10
|
+
- Exit code `0` means no issues were found.
|
|
11
|
+
- Exit code `1` means the command found packages matching the configured dependency policy (advisories and/or abandoned status, depending on `config.policy` settings) or failed due to missing required packages.
|
|
12
|
+
- `config.policy.advisories.audit` controls how `composer audit` treats packages with security advisories. Its allowed values are `ignore` (advisories not reported), `report` (advisories reported but do not cause a non-zero exit code), and `fail` (advisories cause a non-zero exit code). The documented default is `fail`.
|
|
13
|
+
- The `audit` command supports flags including `--no-dev` (skip `require-dev` packages), `--format` (table, plain, json, or summary), `--locked` (audit from the lock file instead of the installed `vendor` directory), and `--ignore-severity` (filter out advisories below a given severity).
|
|
14
|
+
|
|
15
|
+
## Reviewer evidence criteria
|
|
16
|
+
|
|
17
|
+
- Locate every CI job that builds, tests, or deploys the project. For each one, search for an invocation of `composer audit` (or `composer audit --locked`, or an equivalent wrapper script).
|
|
18
|
+
- If no such invocation exists in any relevant pipeline, this is a blocking finding: no CI gate exists at all.
|
|
19
|
+
- If an invocation exists, check whether its exit code is allowed to fail the job. Look for patterns that suppress failure: a trailing `|| true`, a shell `set +e` around the call, a CI step marked `continue-on-error: true` (or equivalent), or output redirected to a report file with no subsequent check of the exit code. Any of these means the audit runs but does not gate — treat it as equivalent to no gate, and cite the specific suppression pattern found.
|
|
20
|
+
- Check `composer.json` for an explicit `config.policy.advisories.audit` value. If set to `ignore` or `report`, this weakens or removes the gate regardless of what CI does with the exit code — flag it, and look for an accompanying documented accepted-risk rationale before treating it as intentional.
|
|
21
|
+
- If `config.policy.advisories.audit` is unset, the documented default (`fail`) applies — verify this is consistent with the project's actual Composer version constraint before relying on it (see abandoned-and-advisory-governance.md for the version-sensitivity of related defaults).
|
|
22
|
+
- If `--locked` is not used and the pipeline audits only the installed `vendor` directory, note that a `vendor` directory that is regenerated fresh in CI from `composer.lock` should produce equivalent results, but flag if the pipeline's install step and audit step could diverge (e.g. cached `vendor` directories, conditional installs).
|
|
23
|
+
- Never assert a specific advisory ID or CVE number exists for a package unless it is directly present in retrieved audit output, a lockfile annotation, or another concrete artifact in the repository.
|
|
24
|
+
|
|
25
|
+
## RECOMMENDATION
|
|
26
|
+
|
|
27
|
+
- Run `composer audit --locked` in CI immediately after dependency installation, as an explicit step whose failure is not caught or suppressed by later pipeline logic.
|
|
28
|
+
- Keep `config.policy.advisories.audit` at its documented default (`fail`) unless there is a written, time-bound, accepted-risk exception for a specific advisory.
|
|
29
|
+
|
|
30
|
+
## Sources
|
|
31
|
+
|
|
32
|
+
- `composer audit` behavior, exit codes, and CLI flags: [Composer CLI documentation](https://getcomposer.org/doc/03-cli.md).
|
|
33
|
+
- `config.policy.advisories.audit` key, allowed values, and default: [Composer config documentation](https://getcomposer.org/doc/06-config.md).
|
|
34
|
+
|
|
35
|
+
Last verified: 2026-07-16
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Lockfile Integrity
|
|
2
|
+
|
|
3
|
+
## Why this matters
|
|
4
|
+
|
|
5
|
+
`composer.lock` is what turns a dependency tree from "whatever the constraints in `composer.json` happen to resolve to today" into a reproducible, reviewable set of exact versions. Without it, or with a drifted or bypassed one, the versions actually running in production are not the versions anyone reviewed — which is precisely the gap OWASP's Vulnerable and Outdated Components category (A06) describes: components are used with unknown or unmanaged versions, making it impossible to know what is actually deployed.
|
|
6
|
+
|
|
7
|
+
## NORMATIVE facts
|
|
8
|
+
|
|
9
|
+
- `composer update` resolves dependencies against `composer.json` and writes the exact resolved package versions to `composer.lock`.
|
|
10
|
+
- `composer install`, when a lock file is present, uses the exact versions recorded in `composer.lock` rather than re-resolving from `composer.json` — this is what makes installs consistent across a CI server, production machines, and every developer's environment.
|
|
11
|
+
- Composer displays a warning when running `install` if `composer.lock` has not been updated since changes were made to `composer.json` that could affect dependency resolution — i.e., the lock file and the manifest have drifted apart.
|
|
12
|
+
- For libraries, committing the lock file is documented as not necessary; this exception does not apply to applications, where the lock file is what makes deployment reproducible.
|
|
13
|
+
|
|
14
|
+
## Reviewer evidence criteria
|
|
15
|
+
|
|
16
|
+
- Confirm `composer.lock` exists in the repository for any project that is deployed as an application (not merely a library consumed by others). Its absence is a blocking finding on its own: without it, `composer install` re-resolves against `composer.json` constraints every time, so the exact versions running anywhere are not fixed, recorded, or reviewable.
|
|
17
|
+
- If `composer.lock` exists, check for evidence of drift from `composer.json` — a captured CI log showing the "lock file is not up to date" warning, a lock content-hash field that does not match the current `composer.json`, or `composer.json` constraints whose ranges no longer contain the versions actually locked. Report drift as a distinct finding from lock absence; a stale lock file is not the same failure as no lock file, and the remediation differs (run `composer update` for the affected packages and commit the refreshed lock, rather than generating a lock file from scratch).
|
|
18
|
+
- With or without an up-to-date lock file, separately review `composer.json` version constraints for packages at security-sensitive boundaries (authentication, cryptography, session handling, serialization/deserialization, payment processing, or any package with a documented prior advisory). Flag unpinned or unusually wide constraints (`*`, unconstrained `dev-` branch references, or a `~`/`^` floor wide enough to span multiple major or minor lines) — a lock file freezes today's resolution, but an unattended future `composer update` against a wide constraint can still move far without anyone reviewing the jump.
|
|
19
|
+
- When recommending remediation, name the exact Composer command that would resolve the finding (e.g. `composer update <package>` to refresh a stale lock entry, or tightening a constraint in `composer.json`) for the owning engineer to run — this skill never executes it.
|
|
20
|
+
- Treat this as an OWASP A06 (Vulnerable and Outdated Components) instance: the underlying risk is that unmanaged or unknown dependency versions make it impossible to assess exposure, independent of whether any specific advisory currently applies.
|
|
21
|
+
|
|
22
|
+
## Sources
|
|
23
|
+
|
|
24
|
+
- `composer.lock` purpose, `composer install` vs `composer update` behavior, the stale-lock warning, and the library exception: [Composer basic usage documentation](https://getcomposer.org/doc/01-basic-usage.md).
|
|
25
|
+
- Vulnerable and Outdated Components as a named risk category: [OWASP Top Ten](https://owasp.org/www-project-top-ten/).
|
|
26
|
+
|
|
27
|
+
Last verified: 2026-07-16
|