guardian-framework 0.1.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/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +12958 -0
- package/dist/exports.js +12765 -0
- package/package.json +61 -0
- package/templates/languages/go-patterns.md +411 -0
- package/templates/languages/java-patterns.md +545 -0
- package/templates/languages/python-patterns.md +312 -0
- package/templates/languages/rust-patterns.md +232 -0
- package/templates/languages/typescript-patterns.md +313 -0
- package/templates/pi/INDEX.md +437 -0
- package/templates/pi/agent/AGENTS.md +166 -0
- package/templates/pi/agents/architecture-coordinator.md +40 -0
- package/templates/pi/agents/architecture-validator.md +36 -0
- package/templates/pi/agents/bootstrap-implementer.md +37 -0
- package/templates/pi/agents/issue-factory.md +31 -0
- package/templates/pi/agents/operations-validator.md +32 -0
- package/templates/pi/agents/security-validator.md +33 -0
- package/templates/pi/architecture/CHANGELOG.md +78 -0
- package/templates/pi/architecture/decisions/ADR-template.md +76 -0
- package/templates/pi/architecture/diagrams/system-overview.md +159 -0
- package/templates/pi/architecture/modules/module-template.md +152 -0
- package/templates/pi/context/checklists.md +91 -0
- package/templates/pi/context/domain-workflow.md +180 -0
- package/templates/pi/context/output-formats.md +135 -0
- package/templates/pi/context/patterns-base.md +47 -0
- package/templates/pi/context/patterns.md +38 -0
- package/templates/pi/context/project.md +88 -0
- package/templates/pi/domain/exploration.md +93 -0
- package/templates/pi/domain/ubiquitous-language.md +24 -0
- package/templates/pi/extensions/architect-lib/generators.ts +528 -0
- package/templates/pi/extensions/architect-lib/helpers.ts +344 -0
- package/templates/pi/extensions/architect-lib/types.ts +117 -0
- package/templates/pi/extensions/architect.ts +1425 -0
- package/templates/pi/extensions/ask-user-question.ts +579 -0
- package/templates/pi/extensions/bash-guard.ts +556 -0
- package/templates/pi/extensions/config-reload.ts +115 -0
- package/templates/pi/extensions/coordinator.ts +304 -0
- package/templates/pi/extensions/curator.ts +543 -0
- package/templates/pi/extensions/domain-explorer.ts +990 -0
- package/templates/pi/extensions/filechanges.ts +656 -0
- package/templates/pi/extensions/goal-loop.ts +717 -0
- package/templates/pi/extensions/hooks.ts +452 -0
- package/templates/pi/extensions/kanban.ts +547 -0
- package/templates/pi/extensions/pipeline.ts +1246 -0
- package/templates/pi/extensions/plan-mode.ts +209 -0
- package/templates/pi/extensions/project-scaffolder.ts +284 -0
- package/templates/pi/extensions/read-only-mode.ts +192 -0
- package/templates/pi/extensions/redaction.ts +128 -0
- package/templates/pi/extensions/session-persistence.ts +174 -0
- package/templates/pi/extensions/slash-commands.ts +229 -0
- package/templates/pi/extensions/snippets.ts +201 -0
- package/templates/pi/extensions/validation-runner.ts +100 -0
- package/templates/pi/github/agents/architecture-coordinator.agent.md +27 -0
- package/templates/pi/github/agents/architecture-validator.agent.md +20 -0
- package/templates/pi/github/agents/bootstrap-implementer.agent.md +20 -0
- package/templates/pi/github/agents/epic-planner.agent.md +70 -0
- package/templates/pi/github/agents/issue-factory.agent.md +20 -0
- package/templates/pi/github/agents/operations-validator.agent.md +20 -0
- package/templates/pi/github/agents/security-validator.agent.md +20 -0
- package/templates/pi/github/copilot/settings.json +16 -0
- package/templates/pi/github/copilot-instructions.md +155 -0
- package/templates/pi/github/instructions/architecture.instructions.md +71 -0
- package/templates/pi/github/instructions/validation.instructions.md +69 -0
- package/templates/pi/github/workflows/01-planning-workflow.md +75 -0
- package/templates/pi/github/workflows/02-issue-generation-workflow.md +69 -0
- package/templates/pi/github/workflows/03-implementation-workflow.md +80 -0
- package/templates/pi/github/workflows/04-validation-workflow.md +68 -0
- package/templates/pi/preflight_report.json +99 -0
- package/templates/pi/prompts/blueprint-update.md +262 -0
- package/templates/pi/prompts/blueprint-validate.md +218 -0
- package/templates/pi/prompts/bug-fix.md +50 -0
- package/templates/pi/prompts/ci-blueprint.md +131 -0
- package/templates/pi/prompts/context-refresh.md +258 -0
- package/templates/pi/prompts/epic-plan.md +356 -0
- package/templates/pi/prompts/epic-template.md +186 -0
- package/templates/pi/prompts/feature-development.md +131 -0
- package/templates/pi/prompts/git-issues.md +243 -0
- package/templates/pi/prompts/hotfix.md +71 -0
- package/templates/pi/prompts/issue-closeout.md +342 -0
- package/templates/pi/prompts/issue-draft.md +218 -0
- package/templates/pi/prompts/issue-implementation-series.md +173 -0
- package/templates/pi/prompts/issue-merge.md +372 -0
- package/templates/pi/prompts/issue-template-set.md +392 -0
- package/templates/pi/prompts/issue-template.md +207 -0
- package/templates/pi/prompts/pattern-extract.md +269 -0
- package/templates/pi/prompts/plan-to-issues.md +430 -0
- package/templates/pi/prompts/refactoring.md +82 -0
- package/templates/pi/prompts/scope-analyzer.md +254 -0
- package/templates/pi/prompts/sync-check.md +230 -0
- package/templates/pi/scripts/categorize-issues.sh +171 -0
- package/templates/pi/scripts/ci/check_architecture_conformance.sh +748 -0
- package/templates/pi/scripts/ci/check_planning_packet.py +228 -0
- package/templates/pi/scripts/ci/run_hardening_stages.sh +264 -0
- package/templates/pi/scripts/ci/run_preflight.sh +649 -0
- package/templates/pi/scripts/ci/run_stage.sh +193 -0
- package/templates/pi/scripts/ci/stage_docs_policy.sh +82 -0
- package/templates/pi/scripts/ci/stage_integration.sh +3 -0
- package/templates/pi/scripts/ci/stage_lint.sh +130 -0
- package/templates/pi/scripts/ci/stage_migration_verify.sh +3 -0
- package/templates/pi/scripts/ci/stage_package_build.sh +3 -0
- package/templates/pi/scripts/ci/stage_release_readiness.sh +3 -0
- package/templates/pi/scripts/ci/stage_remaining.sh +242 -0
- package/templates/pi/scripts/ci/stage_security.sh +3 -0
- package/templates/pi/scripts/ci/stage_static_analysis.sh +114 -0
- package/templates/pi/scripts/ci/stage_unit.sh +119 -0
- package/templates/pi/scripts/ci/validate_agent_output.py +181 -0
- package/templates/pi/scripts/ci/validate_agent_output.sh +243 -0
- package/templates/pi/scripts/create-feature-branch.sh +136 -0
- package/templates/pi/scripts/create-mr.sh +117 -0
- package/templates/pi/scripts/fetch-issues.sh +131 -0
- package/templates/pi/scripts/generate-architecture.sh +161 -0
- package/templates/pi/scripts/git/close-epic.sh +69 -0
- package/templates/pi/scripts/git/close-issue.sh +35 -0
- package/templates/pi/scripts/git/create-tracking-issue.sh +174 -0
- package/templates/pi/scripts/git/link-issue-to-epic.sh +51 -0
- package/templates/pi/scripts/git/update-tracking-issue.sh +66 -0
- package/templates/pi/scripts/languages/go/validate-architecture.sh +139 -0
- package/templates/pi/scripts/languages/go/validate-canonical.sh +129 -0
- package/templates/pi/scripts/languages/go/validate-ci.sh +132 -0
- package/templates/pi/scripts/languages/go/validate-integration.sh +156 -0
- package/templates/pi/scripts/languages/go/validate-operations.sh +146 -0
- package/templates/pi/scripts/languages/go/validate-security.sh +135 -0
- package/templates/pi/scripts/languages/go/validate-tests.sh +125 -0
- package/templates/pi/scripts/languages/java/validate-annotations.sh +185 -0
- package/templates/pi/scripts/languages/java/validate-architecture.sh +159 -0
- package/templates/pi/scripts/languages/java/validate-canonical.sh +114 -0
- package/templates/pi/scripts/languages/java/validate-ci.sh +269 -0
- package/templates/pi/scripts/languages/java/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/java/validate-operations.sh +142 -0
- package/templates/pi/scripts/languages/java/validate-security.sh +174 -0
- package/templates/pi/scripts/languages/java/validate-spring-architecture.sh +227 -0
- package/templates/pi/scripts/languages/java/validate-tests.sh +159 -0
- package/templates/pi/scripts/languages/python/validate-architecture.sh +99 -0
- package/templates/pi/scripts/languages/python/validate-canonical.sh +124 -0
- package/templates/pi/scripts/languages/python/validate-ci.sh +130 -0
- package/templates/pi/scripts/languages/python/validate-integration.sh +119 -0
- package/templates/pi/scripts/languages/python/validate-operations.sh +107 -0
- package/templates/pi/scripts/languages/python/validate-security.sh +68 -0
- package/templates/pi/scripts/languages/python/validate-tests.sh +102 -0
- package/templates/pi/scripts/languages/rust/validate-architecture.sh +188 -0
- package/templates/pi/scripts/languages/rust/validate-canonical.sh +146 -0
- package/templates/pi/scripts/languages/rust/validate-ci.sh +147 -0
- package/templates/pi/scripts/languages/rust/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/rust/validate-operations.sh +154 -0
- package/templates/pi/scripts/languages/rust/validate-security.sh +153 -0
- package/templates/pi/scripts/languages/rust/validate-tests.sh +150 -0
- package/templates/pi/scripts/languages/typescript/validate-architecture.sh +157 -0
- package/templates/pi/scripts/languages/typescript/validate-canonical.sh +135 -0
- package/templates/pi/scripts/languages/typescript/validate-ci.sh +244 -0
- package/templates/pi/scripts/languages/typescript/validate-integration.sh +166 -0
- package/templates/pi/scripts/languages/typescript/validate-operations.sh +162 -0
- package/templates/pi/scripts/languages/typescript/validate-security.sh +169 -0
- package/templates/pi/scripts/languages/typescript/validate-tests.sh +158 -0
- package/templates/pi/scripts/merge-mr.sh +95 -0
- package/templates/pi/scripts/mr-validation.sh +228 -0
- package/templates/pi/scripts/validate-architecture-readiness.sh +153 -0
- package/templates/pi/scripts/validate-architecture.sh +22 -0
- package/templates/pi/scripts/validate-canonical.sh +22 -0
- package/templates/pi/scripts/validate-ci.sh +37 -0
- package/templates/pi/scripts/validate-integration.sh +22 -0
- package/templates/pi/scripts/validate-operations.sh +22 -0
- package/templates/pi/scripts/validate-security.sh +22 -0
- package/templates/pi/scripts/validate-tests.sh +22 -0
- package/templates/pi/scripts/validate-ubiquitous-language.sh +291 -0
- package/templates/pi/scripts/validation-cache.sh +139 -0
- package/templates/pi/skills/agents/architecture-coordinator.md +178 -0
- package/templates/pi/skills/agents/architecture-generator.md +79 -0
- package/templates/pi/skills/agents/architecture-validator.md +74 -0
- package/templates/pi/skills/agents/ci-mr-validator.md +46 -0
- package/templates/pi/skills/agents/code-developer.md +76 -0
- package/templates/pi/skills/agents/commit.md +46 -0
- package/templates/pi/skills/agents/curator.md +71 -0
- package/templates/pi/skills/agents/debug.md +59 -0
- package/templates/pi/skills/agents/documentation-maintainer.md +36 -0
- package/templates/pi/skills/agents/goal-loop.md +125 -0
- package/templates/pi/skills/agents/hooks.md +122 -0
- package/templates/pi/skills/agents/integration-validator.md +35 -0
- package/templates/pi/skills/agents/issue-creator.md +75 -0
- package/templates/pi/skills/agents/issue-factory.md +143 -0
- package/templates/pi/skills/agents/kanban.md +85 -0
- package/templates/pi/skills/agents/land.md +59 -0
- package/templates/pi/skills/agents/operations-validator.md +43 -0
- package/templates/pi/skills/agents/pipeline.md +113 -0
- package/templates/pi/skills/agents/plan-mode.md +77 -0
- package/templates/pi/skills/agents/pull.md +40 -0
- package/templates/pi/skills/agents/push.md +41 -0
- package/templates/pi/skills/agents/security-validator.md +85 -0
- package/templates/pi/skills/agents/session-persistence.md +119 -0
- package/templates/pi/skills/agents/slash-commands.md +117 -0
- package/templates/pi/skills/agents/snippets.md +99 -0
- package/templates/pi/skills/agents/subagent-registry.md +78 -0
- package/templates/pi/skills/agents/test-validator.md +42 -0
- package/templates/pi/skills/validators/architecture-validator.md +43 -0
- package/templates/pi/skills/validators/ci-validator.md +27 -0
- package/templates/pi/skills/validators/context-compaction.md +73 -0
- package/templates/pi/skills/validators/integration-validator.md +38 -0
- package/templates/pi/skills/validators/model-registry.md +96 -0
- package/templates/pi/skills/validators/operations-validator.md +34 -0
- package/templates/pi/skills/validators/security-guards.md +72 -0
- package/templates/pi/skills/validators/security-validator.md +41 -0
- package/templates/pi/skills/validators/system-prompt-tiers.md +69 -0
- package/templates/pi/skills/validators/test-validator.md +33 -0
- package/templates/pi/types.ts +62 -0
- package/templates/pi/validators/README.md +93 -0
- package/templates/pi/validators/default.toml +209 -0
- package/templates/pi/validators/spring.toml +142 -0
- package/templates/pi/workpad.md +53 -0
- package/templates/project/java/Dockerfile +14 -0
- package/templates/project/java/README.md +40 -0
- package/templates/project/java/pom.xml +132 -0
- package/templates/project/typescript/Dockerfile +15 -0
- package/templates/project/typescript/README.md +29 -0
- package/templates/project/typescript/package.json +23 -0
- package/templates/project/typescript/tsconfig.json +21 -0
- package/templates/workflow.md +123 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate planning packet structure and core gating rules.
|
|
3
|
+
|
|
4
|
+
Deterministic validator for epic planning packets produced by the
|
|
5
|
+
Architecture Coordinator. Checks required sections, valid values, and
|
|
6
|
+
structural consistency before the packet is handed off for issue generation.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python scripts/ci/check_planning_packet.py --input=planning_packet.md
|
|
10
|
+
python scripts/ci/check_planning_packet.py --input=planning_packet.md --json
|
|
11
|
+
|
|
12
|
+
Exit codes:
|
|
13
|
+
0 - Packet is valid
|
|
14
|
+
1 - Validation errors found
|
|
15
|
+
2 - Script error
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import re
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
REQUIRED_SECTIONS = [
|
|
28
|
+
"## Stream classification",
|
|
29
|
+
"## Scope summary",
|
|
30
|
+
"## In scope",
|
|
31
|
+
"## Out of scope",
|
|
32
|
+
"## Impacted layers",
|
|
33
|
+
"## Risk classification",
|
|
34
|
+
"## Dependency graph",
|
|
35
|
+
"## Mandatory validators",
|
|
36
|
+
"## Mandatory CI gates",
|
|
37
|
+
"## Forbidden shortcuts",
|
|
38
|
+
"## First implementation issue recommendation",
|
|
39
|
+
"## Open questions / escalation items",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
ALLOWED_STREAMS = {"feature", "hardening", "migration", "control"}
|
|
43
|
+
ALLOWED_RISKS = {"low", "medium", "high"}
|
|
44
|
+
ALLOWED_CI_GATES = {
|
|
45
|
+
"docs_policy", "architecture_conformance", "lint", "static_analysis",
|
|
46
|
+
"unit", "integration", "security", "migration_verify", "release_readiness",
|
|
47
|
+
}
|
|
48
|
+
REQUIRED_VALIDATORS = {"architecture-validator"}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def extract_section(content: str, heading: str) -> str:
|
|
52
|
+
pattern = re.compile(rf"^{re.escape(heading)}\s*$", re.MULTILINE)
|
|
53
|
+
match = pattern.search(content)
|
|
54
|
+
if not match:
|
|
55
|
+
return ""
|
|
56
|
+
start = match.end()
|
|
57
|
+
next_heading = re.search(r"^##\s+", content[start:], re.MULTILINE)
|
|
58
|
+
end = start + next_heading.start() if next_heading else len(content)
|
|
59
|
+
return content[start:end].strip()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def contains_list_item(section: str) -> bool:
|
|
63
|
+
return bool(re.search(r"^[-*]\s+\S|^\d+\.\s+\S", section, re.MULTILINE))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def normalize_lower(section: str) -> str:
|
|
67
|
+
return re.sub(r"\s+", " ", section).strip().lower()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def parse_dash_items(section: str) -> list[str]:
|
|
71
|
+
items: list[str] = []
|
|
72
|
+
for line in section.splitlines():
|
|
73
|
+
stripped = line.strip()
|
|
74
|
+
if stripped.startswith("- "):
|
|
75
|
+
items.append(stripped[2:].strip())
|
|
76
|
+
return items
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def main() -> int:
|
|
80
|
+
parser = argparse.ArgumentParser(description="Validate planning packet structure")
|
|
81
|
+
parser.add_argument("--input", required=True, help="Path to planning packet markdown")
|
|
82
|
+
parser.add_argument("--json", action="store_true", help="Emit JSON output")
|
|
83
|
+
args = parser.parse_args()
|
|
84
|
+
|
|
85
|
+
input_path = Path(args.input)
|
|
86
|
+
if not input_path.exists():
|
|
87
|
+
print(f"Error: Input file not found: {args.input}", file=sys.stderr)
|
|
88
|
+
return 2
|
|
89
|
+
|
|
90
|
+
content = input_path.read_text(encoding="utf-8")
|
|
91
|
+
checks: list[dict] = []
|
|
92
|
+
errors: list[str] = []
|
|
93
|
+
|
|
94
|
+
# 1. Required sections present
|
|
95
|
+
for section in REQUIRED_SECTIONS:
|
|
96
|
+
if section in content:
|
|
97
|
+
checks.append({"check": f"section:{section}", "status": "pass"})
|
|
98
|
+
else:
|
|
99
|
+
checks.append({"check": f"section:{section}", "status": "fail", "message": f"Missing required section"})
|
|
100
|
+
errors.append(f"Missing required section: {section}")
|
|
101
|
+
|
|
102
|
+
# 2. Stream classification is valid
|
|
103
|
+
stream_section = extract_section(content, "## Stream classification")
|
|
104
|
+
if stream_section:
|
|
105
|
+
stream_lower = normalize_lower(stream_section)
|
|
106
|
+
found_streams = [s for s in ALLOWED_STREAMS if s.lower() in stream_lower]
|
|
107
|
+
if found_streams:
|
|
108
|
+
checks.append({"check": "stream_classification", "status": "pass", "value": found_streams[0]})
|
|
109
|
+
else:
|
|
110
|
+
checks.append({"check": "stream_classification", "status": "fail", "message": f"Stream must be one of: {', '.join(sorted(ALLOWED_STREAMS))}"})
|
|
111
|
+
errors.append("Stream classification must be explicit and valid")
|
|
112
|
+
|
|
113
|
+
# 3. Risk classification is valid
|
|
114
|
+
risk_section = extract_section(content, "## Risk classification")
|
|
115
|
+
if risk_section:
|
|
116
|
+
risk_lower = normalize_lower(risk_section)
|
|
117
|
+
found_risks = [r for r in ALLOWED_RISKS if r in risk_lower]
|
|
118
|
+
if found_risks:
|
|
119
|
+
checks.append({"check": "risk_classification", "status": "pass", "value": found_risks[0]})
|
|
120
|
+
else:
|
|
121
|
+
checks.append({"check": "risk_classification", "status": "fail", "message": f"Risk must be one of: {', '.join(sorted(ALLOWED_RISKS))}"})
|
|
122
|
+
errors.append("Risk classification must be explicit and valid")
|
|
123
|
+
|
|
124
|
+
# 4. In scope has items
|
|
125
|
+
in_scope = extract_section(content, "## In scope")
|
|
126
|
+
if in_scope:
|
|
127
|
+
if contains_list_item(in_scope):
|
|
128
|
+
checks.append({"check": "in_scope_items", "status": "pass"})
|
|
129
|
+
else:
|
|
130
|
+
checks.append({"check": "in_scope_items", "status": "fail", "message": "In scope section must contain bullet items"})
|
|
131
|
+
errors.append("In scope section must have at least one bullet item")
|
|
132
|
+
|
|
133
|
+
# 5. Out of scope has items
|
|
134
|
+
out_scope = extract_section(content, "## Out of scope")
|
|
135
|
+
if out_scope:
|
|
136
|
+
if contains_list_item(out_scope):
|
|
137
|
+
checks.append({"check": "out_of_scope_items", "status": "pass"})
|
|
138
|
+
else:
|
|
139
|
+
checks.append({"check": "out_of_scope_items", "status": "fail", "message": "Out of scope section must contain bullet items"})
|
|
140
|
+
errors.append("Out of scope section must have at least one bullet item")
|
|
141
|
+
|
|
142
|
+
# 6. Impacted layers identified
|
|
143
|
+
layers_section = extract_section(content, "## Impacted layers")
|
|
144
|
+
if layers_section and contains_list_item(layers_section):
|
|
145
|
+
checks.append({"check": "impacted_layers", "status": "pass"})
|
|
146
|
+
else:
|
|
147
|
+
checks.append({"check": "impacted_layers", "status": "fail", "message": "Impacted layers section must contain bullet items"})
|
|
148
|
+
errors.append("Impacted layers must be listed")
|
|
149
|
+
|
|
150
|
+
# 7. Dependency graph has items
|
|
151
|
+
dep_section = extract_section(content, "## Dependency graph")
|
|
152
|
+
if dep_section and contains_list_item(dep_section):
|
|
153
|
+
checks.append({"check": "dependency_graph", "status": "pass"})
|
|
154
|
+
else:
|
|
155
|
+
checks.append({"check": "dependency_graph", "status": "fail", "message": "Dependency graph section must contain ordered items"})
|
|
156
|
+
errors.append("Dependency graph must be specified")
|
|
157
|
+
|
|
158
|
+
# 8. Mandatory validators include architecture-validator
|
|
159
|
+
validators_section = extract_section(content, "## Mandatory validators")
|
|
160
|
+
if validators_section:
|
|
161
|
+
items = parse_dash_items(validators_section)
|
|
162
|
+
items_lower = [i.lower() for i in items]
|
|
163
|
+
if any("architecture" in i for i in items_lower):
|
|
164
|
+
checks.append({"check": "mandatory_validators", "status": "pass"})
|
|
165
|
+
else:
|
|
166
|
+
checks.append({"check": "mandatory_validators", "status": "fail", "message": f"Architecture validator is mandatory"})
|
|
167
|
+
errors.append("Architecture Validator must be in mandatory validators")
|
|
168
|
+
else:
|
|
169
|
+
checks.append({"check": "mandatory_validators", "status": "fail", "message": "Section not found"})
|
|
170
|
+
|
|
171
|
+
# 9. CI gates are valid
|
|
172
|
+
ci_section = extract_section(content, "## Mandatory CI gates")
|
|
173
|
+
if ci_section:
|
|
174
|
+
items = parse_dash_items(ci_section)
|
|
175
|
+
invalid = [i for i in items if i not in ALLOWED_CI_GATES]
|
|
176
|
+
if invalid:
|
|
177
|
+
checks.append({"check": "ci_gates", "status": "fail", "message": f"Unknown CI gates: {', '.join(invalid)}"})
|
|
178
|
+
errors.append(f"Unknown CI gates: {', '.join(invalid)}")
|
|
179
|
+
elif items:
|
|
180
|
+
checks.append({"check": "ci_gates", "status": "pass", "value": items})
|
|
181
|
+
else:
|
|
182
|
+
checks.append({"check": "ci_gates", "status": "fail", "message": "No CI gates specified"})
|
|
183
|
+
errors.append("At least one CI gate must be specified")
|
|
184
|
+
else:
|
|
185
|
+
checks.append({"check": "ci_gates", "status": "fail", "message": "Section not found"})
|
|
186
|
+
|
|
187
|
+
# 10. First issue recommendation exists
|
|
188
|
+
first_issue = extract_section(content, "## First implementation issue recommendation")
|
|
189
|
+
if first_issue and len(first_issue) > 10:
|
|
190
|
+
checks.append({"check": "first_issue_recommendation", "status": "pass"})
|
|
191
|
+
else:
|
|
192
|
+
checks.append({"check": "first_issue_recommendation", "status": "fail", "message": "First implementation issue must be recommended"})
|
|
193
|
+
errors.append("First implementation issue must be recommended")
|
|
194
|
+
|
|
195
|
+
# Summary
|
|
196
|
+
passed = sum(1 for c in checks if c["status"] == "pass")
|
|
197
|
+
failed = sum(1 for c in checks if c["status"] == "fail")
|
|
198
|
+
|
|
199
|
+
if args.json:
|
|
200
|
+
output = {
|
|
201
|
+
"input": str(input_path),
|
|
202
|
+
"timestamp": __import__("datetime").datetime.utcnow().isoformat() + "Z",
|
|
203
|
+
"summary": {"total": len(checks), "passed": passed, "failed": failed},
|
|
204
|
+
"checks": checks,
|
|
205
|
+
"errors": errors,
|
|
206
|
+
"status": "pass" if failed == 0 else "fail",
|
|
207
|
+
}
|
|
208
|
+
print(json.dumps(output, indent=2))
|
|
209
|
+
else:
|
|
210
|
+
print(f"\nPlanning Packet Validation: {args.input}")
|
|
211
|
+
print(f"{'='*50}")
|
|
212
|
+
for check in checks:
|
|
213
|
+
icon = "PASS" if check["status"] == "pass" else "FAIL"
|
|
214
|
+
print(f" [{icon}] {check['check']}")
|
|
215
|
+
if check["status"] == "fail" and "message" in check:
|
|
216
|
+
print(f" {check['message']}")
|
|
217
|
+
print(f"\nSummary: {passed} passed, {failed} failed, {len(checks)} total")
|
|
218
|
+
if errors:
|
|
219
|
+
print(f"\nErrors ({len(errors)}):")
|
|
220
|
+
for e in errors:
|
|
221
|
+
print(f" - {e}")
|
|
222
|
+
print(f"\nResult: {'VALID' if failed == 0 else 'INVALID'}")
|
|
223
|
+
|
|
224
|
+
return 0 if failed == 0 else 1
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
if __name__ == "__main__":
|
|
228
|
+
sys.exit(main())
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hardening Stage Runner
|
|
3
|
+
#
|
|
4
|
+
# Runs all 10 hardening stages as defined in the architecture pipeline.
|
|
5
|
+
# Each stage runs its scripts and reports pass/fail.
|
|
6
|
+
# A stage failure prevents MR merge (allow_failure: No).
|
|
7
|
+
#
|
|
8
|
+
# Usage: bash .pi/scripts/ci/run_hardening_stages.sh [--stages <list>] [--verbose]
|
|
9
|
+
#
|
|
10
|
+
# Stages:
|
|
11
|
+
# 1. docs_policy — MR traceability, docs sync guard
|
|
12
|
+
# 2. architecture_conformance — 11+ architectural contract checks
|
|
13
|
+
# 3. lint — ruff/format/coverage
|
|
14
|
+
# 4. static_analysis — mypy/sonar/import-boundaries/sanity
|
|
15
|
+
# 5. unit — domain/app/contract/verification tests
|
|
16
|
+
# 6. integration — integration tests
|
|
17
|
+
# 7. security — SBOM/Trivy/secret scan/deps audit
|
|
18
|
+
# 8. migration_verify — Migration checks (conditional)
|
|
19
|
+
# 9. package_build — Docker build (conditional, main only)
|
|
20
|
+
# 10. release_readiness — Runbook/observability/policy checks
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
PI_DIR=".pi"
|
|
25
|
+
SCRIPTS_DIR="${PI_DIR}/scripts/ci"
|
|
26
|
+
CI_DIR="${PI_DIR}/ci"
|
|
27
|
+
|
|
28
|
+
# Color output
|
|
29
|
+
RED='\033[0;31m'
|
|
30
|
+
GREEN='\033[0;32m'
|
|
31
|
+
YELLOW='\033[1;33m'
|
|
32
|
+
BLUE='\033[0;34m'
|
|
33
|
+
NC='\033[0m'
|
|
34
|
+
|
|
35
|
+
VERBOSE=false
|
|
36
|
+
ALL_STAGES=true
|
|
37
|
+
SELECTED_STAGES=()
|
|
38
|
+
|
|
39
|
+
# Parse arguments
|
|
40
|
+
while [[ $# -gt 0 ]]; do
|
|
41
|
+
case $1 in
|
|
42
|
+
--stages)
|
|
43
|
+
ALL_STAGES=false
|
|
44
|
+
IFS=',' read -ra SELECTED_STAGES <<< "$2"
|
|
45
|
+
shift 2
|
|
46
|
+
;;
|
|
47
|
+
--verbose)
|
|
48
|
+
VERBOSE=true
|
|
49
|
+
shift
|
|
50
|
+
;;
|
|
51
|
+
*)
|
|
52
|
+
shift
|
|
53
|
+
;;
|
|
54
|
+
esac
|
|
55
|
+
done
|
|
56
|
+
|
|
57
|
+
should_run_stage() {
|
|
58
|
+
local stage="$1"
|
|
59
|
+
if [[ "$ALL_STAGES" == "true" ]]; then
|
|
60
|
+
return 0
|
|
61
|
+
fi
|
|
62
|
+
for s in "${SELECTED_STAGES[@]}"; do
|
|
63
|
+
if [[ "$s" == "$stage" ]]; then
|
|
64
|
+
return 0
|
|
65
|
+
fi
|
|
66
|
+
done
|
|
67
|
+
return 1
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
log_stage_start() {
|
|
71
|
+
echo ""
|
|
72
|
+
echo -e "${BLUE}═══ Stage $1: $2 ═══${NC}"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
log_stage_pass() {
|
|
76
|
+
echo -e " ${GREEN}✓ Stage $1 PASSED${NC}"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
log_stage_fail() {
|
|
80
|
+
echo -e " ${RED}✗ Stage $1 FAILED${NC}"
|
|
81
|
+
echo " $2"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
log_stage_skip() {
|
|
85
|
+
echo -e " ${YELLOW}⊘ Stage $1 SKIPPED${NC} — $2"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
TOTAL_STAGES=0
|
|
89
|
+
PASSED_STAGES=0
|
|
90
|
+
FAILED_STAGES=0
|
|
91
|
+
SKIPPED_STAGES=0
|
|
92
|
+
|
|
93
|
+
declare -a STAGE_RESULTS=()
|
|
94
|
+
|
|
95
|
+
run_stage() {
|
|
96
|
+
local stage_num="$1"
|
|
97
|
+
local stage_name="$2"
|
|
98
|
+
local stage_script="$3"
|
|
99
|
+
local conditional="$4" # "always", "main_only", "migration_only", "sonar_required"
|
|
100
|
+
|
|
101
|
+
if ! should_run_stage "$stage_name"; then
|
|
102
|
+
return 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
((TOTAL_STAGES++))
|
|
106
|
+
|
|
107
|
+
# Check conditional
|
|
108
|
+
case "$conditional" in
|
|
109
|
+
main_only)
|
|
110
|
+
if [[ "${CI_COMMIT_BRANCH:-}" != "main" && "${GITHUB_REF_NAME:-}" != "main" ]]; then
|
|
111
|
+
log_stage_skip "$stage_name" "Not on main branch"
|
|
112
|
+
((SKIPPED_STAGES++))
|
|
113
|
+
return 0
|
|
114
|
+
fi
|
|
115
|
+
;;
|
|
116
|
+
migration_only)
|
|
117
|
+
local has_migration=false
|
|
118
|
+
if command -v git &>/dev/null; then
|
|
119
|
+
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -qE "(alembic|migrations?|database.*schema)"; then
|
|
120
|
+
has_migration=true
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
if [[ "$has_migration" == "false" ]]; then
|
|
124
|
+
log_stage_skip "$stage_name" "No migration changes detected"
|
|
125
|
+
((SKIPPED_STAGES++))
|
|
126
|
+
return 0
|
|
127
|
+
fi
|
|
128
|
+
;;
|
|
129
|
+
sonar_required)
|
|
130
|
+
if [[ -z "${SONAR_TOKEN:-}" || -z "${SONAR_HOST_URL:-}" ]]; then
|
|
131
|
+
log_stage_skip "$stage_name" "SONAR_TOKEN or SONAR_HOST_URL not set"
|
|
132
|
+
((SKIPPED_STAGES++))
|
|
133
|
+
return 0
|
|
134
|
+
fi
|
|
135
|
+
;;
|
|
136
|
+
esac
|
|
137
|
+
|
|
138
|
+
log_stage_start "$stage_num" "$stage_name"
|
|
139
|
+
|
|
140
|
+
if [[ ! -f "$stage_script" ]]; then
|
|
141
|
+
log_stage_skip "$stage_name" "Script not found: $stage_script"
|
|
142
|
+
((SKIPPED_STAGES++))
|
|
143
|
+
return 0
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
local output
|
|
147
|
+
if output=$(bash "$stage_script" 2>&1); then
|
|
148
|
+
log_stage_pass "$stage_name"
|
|
149
|
+
((PASSED_STAGES++))
|
|
150
|
+
STAGE_RESULTS+=("PASS:$stage_name")
|
|
151
|
+
if [[ "$VERBOSE" == "true" ]]; then
|
|
152
|
+
echo "$output"
|
|
153
|
+
fi
|
|
154
|
+
else
|
|
155
|
+
log_stage_fail "$stage_name" "$output"
|
|
156
|
+
((FAILED_STAGES++))
|
|
157
|
+
STAGE_RESULTS+=("FAIL:$stage_name:$(echo "$output" | head -5)")
|
|
158
|
+
fi
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
echo "╔══════════════════════════════════════════════════════╗"
|
|
162
|
+
echo "║ Guardian Hardening Stage Runner ║"
|
|
163
|
+
echo "╚══════════════════════════════════════════════════════╝"
|
|
164
|
+
echo ""
|
|
165
|
+
echo "Commit: ${CI_COMMIT_SHA:-${GITHUB_SHA:-unknown}}"
|
|
166
|
+
echo "Branch: ${CI_COMMIT_BRANCH:-${GITHUB_REF_NAME:-unknown}}"
|
|
167
|
+
echo "Pipeline: ${CI_PIPELINE_ID:-local}"
|
|
168
|
+
echo ""
|
|
169
|
+
|
|
170
|
+
# Stage 1: Docs Policy
|
|
171
|
+
run_stage "1" "docs_policy" \
|
|
172
|
+
"${SCRIPTS_DIR}/stage_docs_policy.sh" \
|
|
173
|
+
"always"
|
|
174
|
+
|
|
175
|
+
# Stage 2: Architecture Conformance
|
|
176
|
+
run_stage "2" "architecture_conformance" \
|
|
177
|
+
"${SCRIPTS_DIR}/check_architecture_conformance.sh" \
|
|
178
|
+
"always"
|
|
179
|
+
|
|
180
|
+
# Stage 3: Lint
|
|
181
|
+
run_stage "3" "lint" \
|
|
182
|
+
"${SCRIPTS_DIR}/stage_lint.sh" \
|
|
183
|
+
"always"
|
|
184
|
+
|
|
185
|
+
# Stage 4: Static Analysis
|
|
186
|
+
run_stage "4" "static_analysis" \
|
|
187
|
+
"${SCRIPTS_DIR}/stage_static_analysis.sh" \
|
|
188
|
+
"always"
|
|
189
|
+
|
|
190
|
+
# Stage 5: Unit Tests
|
|
191
|
+
run_stage "5" "unit" \
|
|
192
|
+
"${SCRIPTS_DIR}/stage_unit.sh" \
|
|
193
|
+
"always"
|
|
194
|
+
|
|
195
|
+
# Stage 6: Integration Tests
|
|
196
|
+
run_stage "6" "integration" \
|
|
197
|
+
"${SCRIPTS_DIR}/stage_integration.sh" \
|
|
198
|
+
"always"
|
|
199
|
+
|
|
200
|
+
# Stage 7: Security
|
|
201
|
+
run_stage "7" "security" \
|
|
202
|
+
"${SCRIPTS_DIR}/stage_security.sh" \
|
|
203
|
+
"always"
|
|
204
|
+
|
|
205
|
+
# Stage 8: Migration Verify (conditional)
|
|
206
|
+
run_stage "8" "migration_verify" \
|
|
207
|
+
"${SCRIPTS_DIR}/stage_migration_verify.sh" \
|
|
208
|
+
"migration_only"
|
|
209
|
+
|
|
210
|
+
# Stage 9: Package Build (conditional)
|
|
211
|
+
run_stage "9" "package_build" \
|
|
212
|
+
"${SCRIPTS_DIR}/stage_package_build.sh" \
|
|
213
|
+
"main_only"
|
|
214
|
+
|
|
215
|
+
# Stage 10: Release Readiness
|
|
216
|
+
run_stage "10" "release_readiness" \
|
|
217
|
+
"${SCRIPTS_DIR}/stage_release_readiness.sh" \
|
|
218
|
+
"always"
|
|
219
|
+
|
|
220
|
+
# ── Summary ──
|
|
221
|
+
|
|
222
|
+
echo ""
|
|
223
|
+
echo "╔══════════════════════════════════════════════════════╗"
|
|
224
|
+
echo "║ Hardening Stage Summary ║"
|
|
225
|
+
echo "╚══════════════════════════════════════════════════════╝"
|
|
226
|
+
echo ""
|
|
227
|
+
|
|
228
|
+
for result in "${STAGE_RESULTS[@]}"; do
|
|
229
|
+
IFS=':' read -ra parts <<< "$result"
|
|
230
|
+
status="${parts[0]}"
|
|
231
|
+
name="${parts[1]}"
|
|
232
|
+
detail="${parts[2]:-}"
|
|
233
|
+
|
|
234
|
+
case "$status" in
|
|
235
|
+
PASS)
|
|
236
|
+
echo -e " ${GREEN}✓${NC} ${name}"
|
|
237
|
+
;;
|
|
238
|
+
FAIL)
|
|
239
|
+
echo -e " ${RED}✗${NC} ${name}"
|
|
240
|
+
if [[ -n "$detail" ]]; then
|
|
241
|
+
echo -e " ${RED}${detail}${NC}"
|
|
242
|
+
fi
|
|
243
|
+
;;
|
|
244
|
+
SKIP)
|
|
245
|
+
echo -e " ${YELLOW}⊘${NC} ${name}"
|
|
246
|
+
;;
|
|
247
|
+
esac
|
|
248
|
+
done
|
|
249
|
+
|
|
250
|
+
echo ""
|
|
251
|
+
echo -e " ${GREEN}Passed: ${PASSED_STAGES}${NC}"
|
|
252
|
+
echo -e " ${RED}Failed: ${FAILED_STAGES}${NC}"
|
|
253
|
+
echo -e " ${YELLOW}Skipped: ${SKIPPED_STAGES}${NC}"
|
|
254
|
+
echo " Total: ${TOTAL_STAGES}"
|
|
255
|
+
echo ""
|
|
256
|
+
|
|
257
|
+
if [[ ${FAILED_STAGES} -gt 0 ]]; then
|
|
258
|
+
echo -e "${RED}✗ Hardening FAILED. ${FAILED_STAGES} stage(s) did not pass.${NC}"
|
|
259
|
+
echo "MR cannot be merged until all mandatory stages pass."
|
|
260
|
+
exit 1
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
echo -e "${GREEN}✓ All hardening stages passed. MR is ready for merge.${NC}"
|
|
264
|
+
exit 0
|