phasegate 0.191.0 → 0.212.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/CHANGELOG.md +20 -0
- package/README.ja.md +52 -15
- package/README.md +39 -11
- package/docs/ADR/030-injection-threat-model-and-trust-root.md +145 -0
- package/docs/guide/hooks-integration.md +50 -1
- package/docs/guide/installation.md +1 -1
- package/docs/guide/quick-vs-full-mode.md +1 -1
- package/docs/guide/skills-overview.md +7 -8
- package/package.json +1 -1
- package/scripts/harness/agent-integration/presentation/phasegate-status-context.ts +131 -63
- package/scripts/harness/agent-integration/presentation/session-start-hook.ts +31 -4
- package/scripts/harness/agent-integration/presentation/spotlight.ts +65 -0
- package/scripts/harness/ci-governance/application/dto/pin-integrity-input.ts +8 -0
- package/scripts/harness/ci-governance/application/dto/pin-integrity-output.ts +9 -0
- package/scripts/harness/ci-governance/application/dto/verify-integrity-input.ts +7 -0
- package/scripts/harness/ci-governance/application/dto/verify-integrity-output.ts +10 -0
- package/scripts/harness/ci-governance/application/usecases/pin-integrity-usecase.ts +60 -0
- package/scripts/harness/ci-governance/application/usecases/verify-integrity-usecase.ts +46 -0
- package/scripts/harness/ci-governance/composition-root.ts +67 -64
- package/scripts/harness/ci-governance/domain/ports/integrity-manifest-repository-port.ts +14 -0
- package/scripts/harness/ci-governance/domain/ports/sha256-hasher-port.ts +10 -0
- package/scripts/harness/ci-governance/domain/services/integrity-checker.ts +42 -0
- package/scripts/harness/ci-governance/domain/value-objects/integrity-drift.ts +16 -0
- package/scripts/harness/ci-governance/domain/value-objects/integrity-manifest.ts +49 -0
- package/scripts/harness/ci-governance/domain/value-objects/integrity-target.ts +40 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/file-system-sha256-hasher-adapter.ts +17 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/harness-api-command-existence-adapter.ts +7 -73
- package/scripts/harness/ci-governance/infrastructure/adapters/integrity-manifest-json-repository-adapter.ts +83 -0
- package/scripts/harness/ci-governance/presentation/handlers/integrity-handler.ts +76 -0
- package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +53 -28
- package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +33 -8
- package/scripts/harness/harness-api/domain/value-objects/known-harness-commands.ts +90 -0
- package/scripts/harness/installation/application/bundled-skill-selection.ts +2 -5
- package/scripts/harness/main.ts +257 -105
- package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +65 -3
- package/scripts/harness/quick-mode/domain/services/quick-mode-judgment-engine.ts +44 -40
- package/scripts/harness/setup/skill-deployer.ts +2 -4
- package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +82 -49
- package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +87 -58
- package/scripts/harness/validator-system/composition-root.ts +141 -99
- package/scripts/harness/validator-system/domain/ports/coverage-attestation-gating-policy-port.ts +14 -0
- package/scripts/harness/validator-system/domain/ports/injection-scan-policy-port.ts +14 -0
- package/scripts/harness/validator-system/domain/services/coverage-attestation-gating-service.ts +56 -0
- package/scripts/harness/validator-system/domain/services/injection-pattern-scan-service.ts +118 -0
- package/scripts/harness/validator-system/domain/value-objects/coverage-gating-report.ts +67 -0
- package/scripts/harness/validator-system/domain/value-objects/injection-scan-report.ts +55 -0
- package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +35 -31
- package/scripts/harness/validator-system/infrastructure/adapters/adr-foundation-reference-adapter.ts +13 -7
- package/scripts/harness/validator-system/infrastructure/adapters/file-system-coverage-attestation-gating-adapter.ts +87 -0
- package/scripts/harness/validator-system/infrastructure/adapters/file-system-injection-scan-adapter.ts +82 -0
- package/skills/README.md +1 -1
- package/skills/codebase-mapper/SKILL.md +1 -1
- package/skills/consistency-checker/references//343/203/201/343/202/247/343/203/203/343/202/257/343/203/252/343/202/271/343/203/210.md +1 -1
- package/skills/doc-health-checker/SKILL.md +148 -0
- package/skills/release-publisher/SKILL.md +101 -0
- package/skills/skill-creator/SKILL.md +74 -332
- package/skills/story-implementor/SKILL.md +52 -0
- package/skills/story-mapper/SKILL.md +4 -0
- package/skills/story-writer/SKILL.md +9 -0
- package/skills/uiux-designer/references/uiux-design-template.md +4 -4
- package/skills/unit-designer/SKILL.md +3 -1
- package/skills/doc-freshness-checker/SKILL.md +0 -140
- package/skills/implementation-planner/SKILL.md +0 -169
- package/skills/implementation-planner/references/document-structure.md +0 -116
- package/skills/implementation-planner/references/plan-template.md +0 -177
- package/skills/implementation-planner/references/workflow.md +0 -164
- package/skills/pointer-validator/SKILL.md +0 -105
|
@@ -6,77 +6,92 @@
|
|
|
6
6
|
* @work-item-id WI-110 / WI-111 / WI-132 / WI-133 / WI-136 / WI-137 / WI-138 / WI-156
|
|
7
7
|
* @work-item-id WI-217
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { RunQuickModeUseCase } from
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import { FileSystemWorkItemReflectionAdapter } from
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
9
|
+
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { buildPhase2Extensions } from "../phase2-extensions/composition-root.js";
|
|
12
|
+
import { ValidationResultContractMapper } from "./application/mappers/validation-result-contract-mapper.js";
|
|
13
|
+
import { AggregateValidationResultsUseCase } from "./application/use-cases/aggregate-validation-results-usecase.js";
|
|
14
|
+
import { RunFullValidationUseCase } from "./application/use-cases/run-full-validation-usecase.js";
|
|
15
|
+
import { RunL1ValidatorsUseCase } from "./application/use-cases/run-l1-validators-usecase.js";
|
|
16
|
+
import { RunL2ValidatorsUseCase } from "./application/use-cases/run-l2-validators-usecase.js";
|
|
17
|
+
import { RunL3ValidatorsUseCase } from "./application/use-cases/run-l3-validators-usecase.js";
|
|
18
|
+
import { RunL4ValidatorsUseCase } from "./application/use-cases/run-l4-validators-usecase.js";
|
|
19
|
+
import { RunQuickModeUseCase } from "./application/use-cases/run-quick-mode-usecase.js";
|
|
20
|
+
import {
|
|
21
|
+
ArchitectureSemanticAnalysisService,
|
|
22
|
+
type ArchitectureSemanticPolicy,
|
|
23
|
+
} from "./domain/services/l4/architecture-semantic-analysis-service.js";
|
|
24
|
+
import { ConsistencyCheckService } from "./domain/services/l4/consistency-check-service.js";
|
|
25
|
+
import { DeadCodeDetectionService } from "./domain/services/l4/dead-code-detection-service.js";
|
|
26
|
+
import { DriftDetectionService } from "./domain/services/l4/drift-detection-service.js";
|
|
27
|
+
import { ValidatorExecutionService } from "./domain/services/validator-execution-service.js";
|
|
28
|
+
import { ValidatorRegistry } from "./domain/services/validator-registry.js";
|
|
29
|
+
import { ValidationRule } from "./domain/value-objects/validation-rule.js";
|
|
30
|
+
import { ValidatorDefinition } from "./domain/value-objects/validator-definition.js";
|
|
31
|
+
import { ValidatorId } from "./domain/value-objects/validator-id.js";
|
|
32
|
+
import { AdrFoundationReferenceAdapter } from "./infrastructure/adapters/adr-foundation-reference-adapter.js";
|
|
33
|
+
import { AstPerformanceScannerAdapter } from "./infrastructure/adapters/ast-performance-scanner-adapter.js";
|
|
34
|
+
import { BiomeAstSourceCodeAnalyzerAdapter } from "./infrastructure/adapters/biome-ast-source-code-analyzer-adapter.js";
|
|
35
|
+
import { BiomeAstTestQualityAnalyzerAdapter } from "./infrastructure/adapters/biome-ast-test-quality-analyzer-adapter.js";
|
|
36
|
+
import { CliCommandRegistryAdapter } from "./infrastructure/adapters/cli-command-registry-adapter.js";
|
|
37
|
+
import { E2eTestFileRegistryAdapter } from "./infrastructure/adapters/e2e-test-file-registry-adapter.js";
|
|
38
|
+
import { FileSystemArchitectureSemanticSourceAdapter } from "./infrastructure/adapters/file-system-architecture-semantic-source-adapter.js";
|
|
39
|
+
import { FileSystemContractTraceabilityPolicyAdapter } from "./infrastructure/adapters/file-system-contract-traceability-policy-adapter.js";
|
|
40
|
+
import { FileSystemCoverageAttestationGatingAdapter } from "./infrastructure/adapters/file-system-coverage-attestation-gating-adapter.js";
|
|
41
|
+
import { FileSystemInjectionScanAdapter } from "./infrastructure/adapters/file-system-injection-scan-adapter.js";
|
|
42
|
+
import { FileSystemSecurityPatternScannerAdapter } from "./infrastructure/adapters/file-system-security-pattern-scanner-adapter.js";
|
|
43
|
+
import { FileSystemSkillCatalogDriftAdapter } from "./infrastructure/adapters/file-system-skill-catalog-drift-adapter.js";
|
|
44
|
+
import { FileSystemWorkItemReflectionAdapter } from "./infrastructure/adapters/file-system-work-item-reflection-adapter.js";
|
|
45
|
+
import { HarnessConfigValidatorConfigAdapter } from "./infrastructure/adapters/harness-config-validator-config-adapter.js";
|
|
46
|
+
import { ImportGraphSourceAnalysisAdapter } from "./infrastructure/adapters/import-graph-source-analysis-adapter.js";
|
|
47
|
+
import { ItTestFileAnalyzerAdapter } from "./infrastructure/adapters/it-test-file-analyzer-adapter.js";
|
|
48
|
+
import { JsonCoverageReportAdapter } from "./infrastructure/adapters/json-coverage-report-adapter.js";
|
|
49
|
+
import { MarkdownDesignDocumentAdapter } from "./infrastructure/adapters/markdown-design-document-adapter.js";
|
|
50
|
+
import { NyquistAcBoundCoveragePolicyAdapter } from "./infrastructure/adapters/nyquist-ac-bound-coverage-policy-adapter.js";
|
|
51
|
+
import { NyquistAcCoveragePolicyAdapter } from "./infrastructure/adapters/nyquist-ac-coverage-policy-adapter.js";
|
|
52
|
+
import { NyquistAcLevelTraceabilityAdapter } from "./infrastructure/adapters/nyquist-ac-level-traceability-adapter.js";
|
|
53
|
+
import { PhaseDependencyPhaseGatePolicyAdapter } from "./infrastructure/adapters/phase-dependency-phase-gate-policy-adapter.js";
|
|
54
|
+
import { SourceFileTextScannerAdapter } from "./infrastructure/adapters/source-file-text-scanner-adapter.js";
|
|
55
|
+
import { TraceabilityMetadataPolicyAdapter } from "./infrastructure/adapters/traceability-metadata-policy-adapter.js";
|
|
56
|
+
import { TraceabilityWorkItemStatusPolicyAdapter } from "./infrastructure/adapters/traceability-work-item-status-policy-adapter.js";
|
|
57
|
+
import { ReportValidationResultsHandler } from "./presentation/handlers/report-validation-results-handler.js";
|
|
58
|
+
import { RunQuickModeHandler } from "./presentation/handlers/run-quick-mode-handler.js";
|
|
59
|
+
import { RunValidatorsHandler } from "./presentation/handlers/run-validators-handler.js";
|
|
54
60
|
|
|
55
61
|
/** デフォルト設定(ハードコード fallback) */
|
|
56
62
|
const DEFAULT_CONFIG = {
|
|
57
|
-
preset:
|
|
63
|
+
preset: "standard" as const,
|
|
58
64
|
layers: {
|
|
59
|
-
L2: { enabled: true, validators: [
|
|
60
|
-
L3: {
|
|
61
|
-
|
|
65
|
+
L2: { enabled: true, validators: ["L2-001", "L2-002", "L2-003", "L2-013", "L2-014", "L2-015", "L2-016"] },
|
|
66
|
+
L3: {
|
|
67
|
+
enabled: true,
|
|
68
|
+
validators: ["L3-001", "L3-002", "L3-003", "L3-004", "L3-006"],
|
|
69
|
+
coverageThreshold: 90,
|
|
70
|
+
bundleSizeLimit: 512000,
|
|
71
|
+
requirementMatrixPath: ".harness/requirement-test-matrix.json",
|
|
72
|
+
},
|
|
73
|
+
L4: { enabled: true, validators: ["L4-001", "L4-002", "L4-003", "L4-004", "L4-005", "L4-006"] },
|
|
62
74
|
},
|
|
63
75
|
paths: {
|
|
64
|
-
designDocs:
|
|
65
|
-
inceptionDocs:
|
|
76
|
+
designDocs: "docs/product/construction",
|
|
77
|
+
inceptionDocs: "docs/inception",
|
|
66
78
|
},
|
|
67
79
|
validate: { failOnWarning: false },
|
|
68
80
|
architecture: {
|
|
69
81
|
capabilityPolicies: {
|
|
70
|
-
domain: { allowed: [], denied: [
|
|
71
|
-
application: { allowed: [
|
|
72
|
-
infrastructure: {
|
|
73
|
-
|
|
82
|
+
domain: { allowed: [], denied: ["filesystem", "network", "database", "process-env", "subprocess", "user-io"] },
|
|
83
|
+
application: { allowed: ["time", "random"], denied: ["filesystem", "network", "database", "subprocess"] },
|
|
84
|
+
infrastructure: {
|
|
85
|
+
allowed: ["filesystem", "network", "database", "process-env", "time", "random", "subprocess", "user-io"],
|
|
86
|
+
denied: [],
|
|
87
|
+
},
|
|
88
|
+
presentation: { allowed: ["user-io", "time"], denied: ["database", "subprocess"] },
|
|
74
89
|
},
|
|
75
90
|
decisionPolicies: {
|
|
76
|
-
domain: { expected: [
|
|
77
|
-
application: { expected: [
|
|
78
|
-
infrastructure: { expected: [
|
|
79
|
-
presentation: { expected: [
|
|
91
|
+
domain: { expected: ["business-rule-branch", "validation-rule", "state-transition"], advisoryOnly: true },
|
|
92
|
+
application: { expected: ["policy-selection", "error-construction"], advisoryOnly: true },
|
|
93
|
+
infrastructure: { expected: ["error-construction"], advisoryOnly: true },
|
|
94
|
+
presentation: { expected: ["validation-rule", "error-construction"], advisoryOnly: true },
|
|
80
95
|
},
|
|
81
96
|
},
|
|
82
97
|
};
|
|
@@ -84,47 +99,58 @@ const DEFAULT_CONFIG = {
|
|
|
84
99
|
/** バリデータ定義カタログ */
|
|
85
100
|
export function buildDefaultRegistry(): ValidatorRegistry {
|
|
86
101
|
const defaultRule = ValidationRule.create({
|
|
87
|
-
ruleName:
|
|
88
|
-
errorTemplate: { code:
|
|
102
|
+
ruleName: "default-rule",
|
|
103
|
+
errorTemplate: { code: "L2-001", severity: "error", messageTemplate: "{{message}}" },
|
|
89
104
|
fixExample: null,
|
|
90
105
|
});
|
|
91
106
|
|
|
92
|
-
const createDef = (
|
|
107
|
+
const createDef = (
|
|
108
|
+
id: string,
|
|
109
|
+
layer: "L2" | "L3" | "L4",
|
|
110
|
+
enabledCondition: "always" | "strictOnly" = "always",
|
|
111
|
+
externalPolicyRef: string | null = null,
|
|
112
|
+
) =>
|
|
93
113
|
ValidatorDefinition.create({
|
|
94
114
|
validatorId: ValidatorId.create(id),
|
|
95
115
|
layer,
|
|
96
|
-
rules: [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
rules: [
|
|
117
|
+
ValidationRule.create({
|
|
118
|
+
ruleName: `${id}-rule`,
|
|
119
|
+
errorTemplate: { code: id, severity: "error", messageTemplate: "{{message}}" },
|
|
120
|
+
fixExample: null,
|
|
121
|
+
}),
|
|
122
|
+
],
|
|
101
123
|
enabledCondition,
|
|
102
124
|
externalPolicyRef,
|
|
103
125
|
});
|
|
104
126
|
|
|
105
127
|
const definitions = [
|
|
106
|
-
createDef(
|
|
107
|
-
createDef(
|
|
108
|
-
createDef(
|
|
109
|
-
createDef(
|
|
110
|
-
createDef(
|
|
111
|
-
createDef(
|
|
112
|
-
|
|
113
|
-
createDef(
|
|
114
|
-
createDef(
|
|
115
|
-
createDef(
|
|
128
|
+
createDef("L2-001", "L2", "always", "PhaseGatePolicyPort"),
|
|
129
|
+
createDef("L2-002", "L2", "always", "MetadataPolicyPort"),
|
|
130
|
+
createDef("L2-003", "L2", "always"),
|
|
131
|
+
createDef("L2-013", "L2", "always", "CliE2eTestExistenceService"),
|
|
132
|
+
createDef("L2-014", "L2", "always", "WorkItemStatusPolicyPort"),
|
|
133
|
+
createDef("L2-015", "L2", "always", "ContractTraceabilityPolicyPort"),
|
|
134
|
+
// WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating, fail-closed, default-ON)。
|
|
135
|
+
createDef("L2-016", "L2", "always", "CoverageAttestationGatingPolicyPort"),
|
|
136
|
+
createDef("L3-001", "L3", "always"),
|
|
137
|
+
createDef("L3-002", "L3", "strictOnly"),
|
|
138
|
+
createDef("L3-003", "L3", "always"),
|
|
139
|
+
createDef("L3-004", "L3", "always", "AcCoveragePolicyPort"),
|
|
116
140
|
// WI-227 / H16-03: L3-005 (ac-bound-coverage) は registry には登録するが
|
|
117
141
|
// default-OFF(DEFAULT_CONFIG.layers.L3.validators に含めない)。fail-closed / opt-in。
|
|
118
|
-
createDef(
|
|
119
|
-
|
|
120
|
-
createDef(
|
|
121
|
-
createDef(
|
|
122
|
-
createDef(
|
|
123
|
-
createDef(
|
|
124
|
-
createDef(
|
|
142
|
+
createDef("L3-005", "L3", "always", "AcBoundCoveragePolicyPort"),
|
|
143
|
+
// WI-259 / ADR-030 §Decision.3.④: L3-006 (injection-scan) は advisory (warning-only, default-ON)。
|
|
144
|
+
createDef("L3-006", "L3", "always", "InjectionScanPolicyPort"),
|
|
145
|
+
createDef("L4-001", "L4", "always"),
|
|
146
|
+
createDef("L4-002", "L4", "always"),
|
|
147
|
+
createDef("L4-003", "L4", "strictOnly"),
|
|
148
|
+
createDef("L4-004", "L4", "always"),
|
|
149
|
+
createDef("L4-005", "L4", "always"),
|
|
150
|
+
createDef("L4-006", "L4", "always", "SkillCatalogDriftPort"),
|
|
125
151
|
// WI-222 / HF2-05: L4-007 (ac-level-traceability) は registry には登録するが
|
|
126
152
|
// default-OFF(DEFAULT_CONFIG.layers.L4.validators に含めない)。advisory-only。
|
|
127
|
-
createDef(
|
|
153
|
+
createDef("L4-007", "L4", "always", "AcLevelTraceabilityPort"),
|
|
128
154
|
];
|
|
129
155
|
|
|
130
156
|
return new ValidatorRegistry(definitions);
|
|
@@ -162,26 +188,40 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
162
188
|
const acBoundCoveragePolicyPort = new NyquistAcBoundCoveragePolicyAdapter();
|
|
163
189
|
// L3-003: テストカバレッジレポート(vitest --coverage の json-summary 出力)を読み取る。
|
|
164
190
|
// 未配線だと L3-003 は装飾的な pass になり 90% 閾値が形骸化するため必ず配線する。
|
|
165
|
-
const coverageReportPort = new JsonCoverageReportAdapter(
|
|
166
|
-
join(process.cwd(), 'coverage', 'coverage-summary.json'),
|
|
167
|
-
);
|
|
191
|
+
const coverageReportPort = new JsonCoverageReportAdapter(join(process.cwd(), "coverage", "coverage-summary.json"));
|
|
168
192
|
const testQualityAnalyzerPort = new BiomeAstTestQualityAnalyzerAdapter();
|
|
169
193
|
const securityScannerPort = new FileSystemSecurityPatternScannerAdapter();
|
|
170
194
|
const performanceScannerPort = new AstPerformanceScannerAdapter();
|
|
171
195
|
const workItemStatusPolicyPort = new TraceabilityWorkItemStatusPolicyAdapter(process.cwd());
|
|
172
196
|
const contractTraceabilityPolicyPort = new FileSystemContractTraceabilityPolicyAdapter();
|
|
197
|
+
// WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating) 用アダプタ。
|
|
198
|
+
// docs/product/construction/*/coverage_report.md を cwd 起点で走査する(targetPaths 非依存)。
|
|
199
|
+
const coverageAttestationGatingPolicyPort = new FileSystemCoverageAttestationGatingAdapter(process.cwd());
|
|
200
|
+
// WI-259 / ADR-030 §Decision.3.④: L3-006 (injection-scan, advisory) 用アダプタ。
|
|
201
|
+
// 指示搭載ファイル群(skills/**/SKILL.md / CLAUDE.md / AGENTS.md / agent-context / .claude/settings.json)を
|
|
202
|
+
// cwd 起点で走査する(targetPaths 非依存)。
|
|
203
|
+
const injectionScanPolicyPort = new FileSystemInjectionScanAdapter(process.cwd());
|
|
173
204
|
|
|
174
205
|
const cwd = process.cwd();
|
|
175
|
-
const designDocsRoot = configData.paths?.designDocs ??
|
|
176
|
-
const inceptionDocsRoot = configData.paths?.inceptionDocs ??
|
|
206
|
+
const designDocsRoot = configData.paths?.designDocs ?? "docs/product/construction";
|
|
207
|
+
const inceptionDocsRoot = configData.paths?.inceptionDocs ?? "docs/inception";
|
|
177
208
|
const docsRoot = join(cwd, designDocsRoot);
|
|
178
|
-
const e2eTestFileRegistryPort = new E2eTestFileRegistryAdapter({
|
|
209
|
+
const e2eTestFileRegistryPort = new E2eTestFileRegistryAdapter({
|
|
210
|
+
e2eTestRoot: join(cwd, "scripts/harness/__tests__/e2e"),
|
|
211
|
+
});
|
|
179
212
|
const cliCommandRegistryPort = new CliCommandRegistryAdapter({
|
|
180
213
|
commands: [
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
214
|
+
"validate",
|
|
215
|
+
"lint",
|
|
216
|
+
"ci-check",
|
|
217
|
+
"phasegate:check-ready",
|
|
218
|
+
"phasegate:check-phase",
|
|
219
|
+
"phasegate:ci-check",
|
|
220
|
+
"phasegate:detect-drift",
|
|
221
|
+
"phasegate:lint",
|
|
222
|
+
"phasegate:complete-check",
|
|
223
|
+
"phasegate:impact-analysis",
|
|
224
|
+
"phasegate:status",
|
|
185
225
|
],
|
|
186
226
|
});
|
|
187
227
|
|
|
@@ -197,6 +237,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
197
237
|
cliCommandRegistryPort,
|
|
198
238
|
workItemStatusPolicyPort,
|
|
199
239
|
contractTraceabilityPolicyPort,
|
|
240
|
+
coverageAttestationGatingPolicyPort,
|
|
200
241
|
});
|
|
201
242
|
|
|
202
243
|
// WI-227 / H16-03: L3-005 のスコープ対象 story-id を config から取得(既定 [])。
|
|
@@ -213,19 +254,20 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
213
254
|
coverageReportPort,
|
|
214
255
|
securityScannerPort,
|
|
215
256
|
performanceScannerPort,
|
|
257
|
+
injectionScanPolicyPort,
|
|
216
258
|
acBoundStories,
|
|
217
259
|
});
|
|
218
260
|
|
|
219
261
|
const markdownDesignDocumentPort = new MarkdownDesignDocumentAdapter(docsRoot);
|
|
220
262
|
const sourceCodeAnalyzerAdapter = new BiomeAstSourceCodeAnalyzerAdapter();
|
|
221
|
-
const adrReferencePort = new AdrFoundationReferenceAdapter();
|
|
263
|
+
const adrReferencePort = new AdrFoundationReferenceAdapter(cwd);
|
|
222
264
|
const sourceAnalysisPort = new ImportGraphSourceAnalysisAdapter();
|
|
223
265
|
const architectureSemanticSourcePort = new FileSystemArchitectureSemanticSourceAdapter();
|
|
224
266
|
const skillCatalogDriftPort = new FileSystemSkillCatalogDriftAdapter(cwd);
|
|
225
267
|
// WI-222 / HF2-05: L4-007 (advisory) 用の AC 単位トレーサビリティ port。
|
|
226
268
|
// matrix path は L3-004 と同じ config キーを参照する。
|
|
227
269
|
const acLevelTraceabilityPort = new NyquistAcLevelTraceabilityAdapter({
|
|
228
|
-
matrixFilePath: configData.layers?.L3?.requirementMatrixPath ??
|
|
270
|
+
matrixFilePath: configData.layers?.L3?.requirementMatrixPath ?? ".harness/requirement-test-matrix.json",
|
|
229
271
|
});
|
|
230
272
|
const workItemReflectionPort = new FileSystemWorkItemReflectionAdapter(cwd);
|
|
231
273
|
|
|
@@ -275,11 +317,11 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
275
317
|
|
|
276
318
|
const aggregateValidationResultsUseCase = new AggregateValidationResultsUseCase();
|
|
277
319
|
const itTestFileAnalyzerPort = new ItTestFileAnalyzerAdapter({
|
|
278
|
-
itTestRoot: join(cwd,
|
|
320
|
+
itTestRoot: join(cwd, "scripts/harness/__tests__/integration"),
|
|
279
321
|
// アダプター自体のテストファイルは vi.mock() を使用しているため誤検知防止で除外
|
|
280
322
|
excludePattern: /it-test-file-analyzer-adapter\.test\.ts$/,
|
|
281
323
|
});
|
|
282
|
-
const sourceFileTextScannerPort = new SourceFileTextScannerAdapter({ sourceRoot: join(cwd,
|
|
324
|
+
const sourceFileTextScannerPort = new SourceFileTextScannerAdapter({ sourceRoot: join(cwd, "scripts/harness") });
|
|
283
325
|
const runL1ValidatorsUseCase = new RunL1ValidatorsUseCase({
|
|
284
326
|
itTestFileAnalyzerPort,
|
|
285
327
|
sourceFileTextScannerPort,
|
package/scripts/harness/validator-system/domain/ports/coverage-attestation-gating-policy-port.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @unit validator-system
|
|
2
|
+
// @layer domain
|
|
3
|
+
// @work-item-id WI-258
|
|
4
|
+
|
|
5
|
+
import type { CoverageReportGatingModel } from "../value-objects/coverage-gating-report.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WI-258 / ADR-030 §Decision.3.② — coverage_report 走査結果の供給ポート。
|
|
9
|
+
* 走査対象(docs/product/construction/*/coverage_report.md)の解決は infrastructure が担う
|
|
10
|
+
* (cwd 起点・targetPaths 非依存の corpus 走査)。
|
|
11
|
+
*/
|
|
12
|
+
export interface CoverageAttestationGatingPolicyPort {
|
|
13
|
+
collect(): Promise<readonly CoverageReportGatingModel[]>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @unit validator-system
|
|
2
|
+
// @layer domain
|
|
3
|
+
// @work-item-id WI-259
|
|
4
|
+
|
|
5
|
+
import type { InjectionScanTarget } from "../value-objects/injection-scan-report.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WI-259 / ADR-030 §Decision.3.④ — 指示搭載ファイルの供給ポート。
|
|
9
|
+
* 走査対象(skills/**/SKILL.md / CLAUDE.md / AGENTS.md / docs/templates/agent-context/** /
|
|
10
|
+
* .claude/settings.json)の解決は infrastructure が担う(cwd 起点・targetPaths 非依存の corpus 走査)。
|
|
11
|
+
*/
|
|
12
|
+
export interface InjectionScanPolicyPort {
|
|
13
|
+
collect(): Promise<readonly InjectionScanTarget[]>;
|
|
14
|
+
}
|
package/scripts/harness/validator-system/domain/services/coverage-attestation-gating-service.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// @unit validator-system
|
|
2
|
+
// @layer domain
|
|
3
|
+
// @work-item-id WI-258
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WI-258 / ADR-030 §Decision.3.② — coverage-attestation-gating (L2-016) の判定ドメインサービス。
|
|
7
|
+
*
|
|
8
|
+
* INV-A: hasLegacyMarker のファイルは error を生成せず legacyCount に計上し warning を 1 件生成(見える負債)。
|
|
9
|
+
* INV-B: マーカー無しファイルで attestation 参照を持たない ✅ claim は error violation(fail-closed)。
|
|
10
|
+
* INV-C: ✅ を持たないファイルは violation も warning も生成しない(対象外)。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
type CoverageGatingFinding,
|
|
15
|
+
CoverageGatingReport,
|
|
16
|
+
type CoverageReportGatingModel,
|
|
17
|
+
} from "../value-objects/coverage-gating-report.js";
|
|
18
|
+
|
|
19
|
+
export class CoverageAttestationGatingService {
|
|
20
|
+
check(models: readonly CoverageReportGatingModel[]): CoverageGatingReport {
|
|
21
|
+
const violations: CoverageGatingFinding[] = [];
|
|
22
|
+
const warnings: CoverageGatingFinding[] = [];
|
|
23
|
+
let legacyCount = 0;
|
|
24
|
+
|
|
25
|
+
for (const model of models) {
|
|
26
|
+
if (model.hasLegacyMarker) {
|
|
27
|
+
// INV-A: 免除だが可視化。claim の有無に関わらず legacy として計上する
|
|
28
|
+
// (マーカーは「このファイルはまだゲートされていない負債」の宣言であるため)。
|
|
29
|
+
legacyCount += 1;
|
|
30
|
+
warnings.push({
|
|
31
|
+
severity: "warning",
|
|
32
|
+
sourcePath: model.path,
|
|
33
|
+
message: `ungated-legacy coverage_report (attestation ゲート未適用の負債): ${model.path}`,
|
|
34
|
+
suggestion:
|
|
35
|
+
"各 ✅ 主張に <!-- @attestation <id> --> を付与し、@coverage-gating: ungated-legacy マーカーを除去して段階返済すること。",
|
|
36
|
+
});
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// INV-B / INV-C: マーカー無しファイルの各 ✅ claim を検査する。
|
|
41
|
+
for (const claim of model.claims) {
|
|
42
|
+
if (!claim.hasAttestationRef) {
|
|
43
|
+
violations.push({
|
|
44
|
+
severity: "error",
|
|
45
|
+
sourcePath: model.path,
|
|
46
|
+
message: `${model.path}:${claim.lineNumber} の ✅ 主張に attestation 参照がありません(bare ✅ は fail-closed)。`,
|
|
47
|
+
suggestion:
|
|
48
|
+
"✅ 主張に <!-- @attestation <id> --> を付与するか、未返済なら <!-- @coverage-gating: ungated-legacy --> マーカーで免除(負債可視化)すること。",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return CoverageGatingReport.create(violations, warnings, legacyCount);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// @unit validator-system
|
|
2
|
+
// @layer domain
|
|
3
|
+
// @work-item-id WI-259
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WI-259 / ADR-030 §Decision.3.④ — advisory インジェクションスキャナ(L3-006)の判定ドメインサービス。
|
|
7
|
+
*
|
|
8
|
+
* 指示搭載ファイル群に対し既知のインジェクションパターンを行単位で照合する純粋サービス。
|
|
9
|
+
* INV-A: 生成する finding は必ず severity='warning'(error / violation を一切生成しない — §4.(b))。
|
|
10
|
+
* INV-B: HTML コメント内の指示上書きは html-comment-instruction に一本化し instruction-override として二重報告しない。
|
|
11
|
+
* INV-C: どのパターンにも該当しない対象は finding を生成しない(無音 → pass)。
|
|
12
|
+
*
|
|
13
|
+
* パターンは narrow に設計し、自リポジトリの正当な文書(散文)に誤検知しないことを実 corpus で実証する。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
type InjectionFinding,
|
|
18
|
+
InjectionScanReport,
|
|
19
|
+
type InjectionScanTarget,
|
|
20
|
+
} from "../value-objects/injection-scan-report.js";
|
|
21
|
+
|
|
22
|
+
/** 指示上書きフレーズ(英/日)。narrow な定型のみ。 */
|
|
23
|
+
const OVERRIDE_PATTERNS: readonly RegExp[] = [
|
|
24
|
+
/ignore\s+(?:all\s+|any\s+)?(?:previous|prior|above)\s+(?:instructions|rules)/i,
|
|
25
|
+
/disregard\s+(?:your|all)\s+(?:instructions|training)/i,
|
|
26
|
+
/これまでの指示を無視/,
|
|
27
|
+
/以前の指示を無視/,
|
|
28
|
+
/上記の指示を無視/,
|
|
29
|
+
/指示を(?:全て|すべて)無視/,
|
|
30
|
+
/システムプロンプトを無視/,
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/** HTML コメントを含む行か(`<!--` の存在で判定。行内コメント・複数行コメント開始のいずれも拾う)。 */
|
|
34
|
+
const HTML_COMMENT_LINE = /<!--/;
|
|
35
|
+
|
|
36
|
+
/** 不可視 Unicode: zero-width (U+200B-U+200D, U+FEFF) + bidi 制御 (U+202A-U+202E, U+2066-U+2069)。 */
|
|
37
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: bidi/zero-width 制御文字の検出が目的
|
|
38
|
+
const INVISIBLE_UNICODE = /[---]/;
|
|
39
|
+
|
|
40
|
+
/** 連続 200 文字以上の base64 文字列塊。 */
|
|
41
|
+
const BASE64_BLOB = /[A-Za-z0-9+/]{200,}={0,2}/;
|
|
42
|
+
|
|
43
|
+
export class InjectionPatternScanService {
|
|
44
|
+
scan(targets: readonly InjectionScanTarget[]): InjectionScanReport {
|
|
45
|
+
const findings: InjectionFinding[] = [];
|
|
46
|
+
|
|
47
|
+
for (const target of targets) {
|
|
48
|
+
const lines = target.content.split(/\r?\n/);
|
|
49
|
+
for (let i = 0; i < lines.length; i++) {
|
|
50
|
+
const line = lines[i];
|
|
51
|
+
const lineNumber = i + 1;
|
|
52
|
+
|
|
53
|
+
const hasOverride = OVERRIDE_PATTERNS.some((pattern) => pattern.test(line));
|
|
54
|
+
if (hasOverride) {
|
|
55
|
+
// INV-B: HTML コメント内の指示上書きは html-comment-instruction に一本化する。
|
|
56
|
+
if (HTML_COMMENT_LINE.test(line)) {
|
|
57
|
+
findings.push(
|
|
58
|
+
this.finding(
|
|
59
|
+
"html-comment-instruction",
|
|
60
|
+
target.path,
|
|
61
|
+
lineNumber,
|
|
62
|
+
"HTML コメント内にエージェント宛ての指示上書きフレーズが埋め込まれています。",
|
|
63
|
+
"隠蔽された指示の可能性があります。人間レビューで意図を確認してください(advisory)。",
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
findings.push(
|
|
68
|
+
this.finding(
|
|
69
|
+
"instruction-override",
|
|
70
|
+
target.path,
|
|
71
|
+
lineNumber,
|
|
72
|
+
"指示上書きフレーズ(例: ignore previous instructions / これまでの指示を無視)を検出しました。",
|
|
73
|
+
"インジェクションの可能性があります。人間レビューで意図を確認してください(advisory)。",
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (INVISIBLE_UNICODE.test(line)) {
|
|
80
|
+
findings.push(
|
|
81
|
+
this.finding(
|
|
82
|
+
"invisible-unicode",
|
|
83
|
+
target.path,
|
|
84
|
+
lineNumber,
|
|
85
|
+
"不可視 Unicode 文字(zero-width / bidi 制御)を検出しました。",
|
|
86
|
+
"見えない文字で指示を隠蔽している可能性があります。人間レビューで確認してください(advisory)。",
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (BASE64_BLOB.test(line)) {
|
|
92
|
+
findings.push(
|
|
93
|
+
this.finding(
|
|
94
|
+
"base64-blob",
|
|
95
|
+
target.path,
|
|
96
|
+
lineNumber,
|
|
97
|
+
"連続 200 文字以上の base64 らしき塊を検出しました。",
|
|
98
|
+
"エンコードされた指示・ペイロードの可能性があります。人間レビューで確認してください(advisory)。",
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return InjectionScanReport.create(findings);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private finding(
|
|
109
|
+
kind: InjectionFinding["kind"],
|
|
110
|
+
sourcePath: string,
|
|
111
|
+
lineNumber: number,
|
|
112
|
+
message: string,
|
|
113
|
+
suggestion: string,
|
|
114
|
+
): InjectionFinding {
|
|
115
|
+
// INV-A: severity は必ず 'warning'。
|
|
116
|
+
return { kind, severity: "warning", sourcePath, lineNumber, message, suggestion };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// @unit validator-system
|
|
2
|
+
// @layer domain
|
|
3
|
+
// @work-item-id WI-258
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WI-258 / ADR-030 §Decision.3.② — coverage_report の attestation ゲート(L2-016)用ドメインモデル。
|
|
7
|
+
*
|
|
8
|
+
* coverage_report.md の ✅ 主張に attestation 参照(`<!-- @attestation <id> -->`)を要求する
|
|
9
|
+
* anti-laundering の value-object 群。L2 は参照の存在・形状のみを検証し(bare ✅ を fail-closed で遮断)、
|
|
10
|
+
* attestation レコードとの authoritative 突合は L3 が担う(ADR-030)。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** 1 件の ✅ 主張(AC が「達成」と主張する行)。 */
|
|
14
|
+
export interface CoverageClaim {
|
|
15
|
+
/** ✅ を含む行番号(1 起点)。 */
|
|
16
|
+
readonly lineNumber: number;
|
|
17
|
+
/** 同一行 or 直前の連続コメント行に `@attestation` 参照があるか。 */
|
|
18
|
+
readonly hasAttestationRef: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** 1 coverage_report ファイルの走査結果。 */
|
|
22
|
+
export interface CoverageReportGatingModel {
|
|
23
|
+
readonly path: string;
|
|
24
|
+
/** `<!-- @coverage-gating: ungated-legacy -->` マーカー(ファイル全体免除)の有無。 */
|
|
25
|
+
readonly hasLegacyMarker: boolean;
|
|
26
|
+
readonly claims: readonly CoverageClaim[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** ゲート判定の 1 finding。 */
|
|
30
|
+
export interface CoverageGatingFinding {
|
|
31
|
+
readonly severity: "error" | "warning";
|
|
32
|
+
readonly sourcePath: string;
|
|
33
|
+
readonly message: string;
|
|
34
|
+
readonly suggestion: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* ゲート判定レポート。violations は fail-closed の error、warnings は legacy 可視化。
|
|
39
|
+
*/
|
|
40
|
+
export class CoverageGatingReport {
|
|
41
|
+
readonly violations: readonly CoverageGatingFinding[];
|
|
42
|
+
readonly warnings: readonly CoverageGatingFinding[];
|
|
43
|
+
readonly legacyCount: number;
|
|
44
|
+
|
|
45
|
+
private constructor(
|
|
46
|
+
violations: readonly CoverageGatingFinding[],
|
|
47
|
+
warnings: readonly CoverageGatingFinding[],
|
|
48
|
+
legacyCount: number,
|
|
49
|
+
) {
|
|
50
|
+
this.violations = Object.freeze([...violations]);
|
|
51
|
+
this.warnings = Object.freeze([...warnings]);
|
|
52
|
+
this.legacyCount = legacyCount;
|
|
53
|
+
Object.freeze(this);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static create(
|
|
57
|
+
violations: readonly CoverageGatingFinding[],
|
|
58
|
+
warnings: readonly CoverageGatingFinding[],
|
|
59
|
+
legacyCount: number,
|
|
60
|
+
): CoverageGatingReport {
|
|
61
|
+
return new CoverageGatingReport(violations, warnings, legacyCount);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
hasViolations(): boolean {
|
|
65
|
+
return this.violations.length > 0;
|
|
66
|
+
}
|
|
67
|
+
}
|