bigpowers 2.76.3 → 2.77.1

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.
Files changed (93) hide show
  1. package/.pi/package.json +2 -2
  2. package/.pi/prompts/audit-code.md +1 -1
  3. package/.pi/prompts/build-epic.md +10 -0
  4. package/.pi/prompts/craft-skill.md +2 -2
  5. package/.pi/prompts/elaborate-spec.md +1 -1
  6. package/.pi/prompts/evolve-skill.md +1 -1
  7. package/.pi/prompts/generate-allure-report.md +284 -0
  8. package/.pi/prompts/grill-me.md +1 -1
  9. package/.pi/prompts/guard-git.md +1 -1
  10. package/.pi/prompts/harden-vps.md +287 -0
  11. package/.pi/prompts/investigate-bug.md +2 -2
  12. package/.pi/prompts/model-domain.md +3 -3
  13. package/.pi/prompts/plan-refactor.md +2 -2
  14. package/.pi/prompts/plan-release.md +5 -10
  15. package/.pi/prompts/plan-work.md +14 -1
  16. package/.pi/prompts/using-bigpowers.md +1 -1
  17. package/.pi/prompts/write-document.md +2 -2
  18. package/.pi/skills/audit-code/SKILL.md +1 -1
  19. package/.pi/skills/build-epic/SKILL.md +10 -0
  20. package/.pi/skills/change-request/SKILL.md +1 -1
  21. package/.pi/skills/commit-message/SKILL.md +3 -3
  22. package/.pi/skills/compose-workflow/SKILL.md +1 -1
  23. package/.pi/skills/craft-skill/SKILL.md +4 -4
  24. package/.pi/skills/deepen-architecture/SKILL.md +13 -13
  25. package/.pi/skills/deploy/SKILL.md +4 -4
  26. package/.pi/skills/develop-tdd/SKILL.md +5 -5
  27. package/.pi/skills/elaborate-spec/SKILL.md +1 -1
  28. package/.pi/skills/evolve-skill/SKILL.md +2 -2
  29. package/.pi/skills/extract-design/SKILL.md +1 -1
  30. package/.pi/skills/generate-allure-report/SKILL.md +285 -0
  31. package/.pi/skills/grill-me/SKILL.md +2 -2
  32. package/.pi/skills/grill-with-docs/SKILL.md +1 -1
  33. package/.pi/skills/guard-git/SKILL.md +5 -5
  34. package/.pi/skills/harden-vps/SKILL.md +288 -0
  35. package/.pi/skills/investigate-bug/SKILL.md +2 -2
  36. package/.pi/skills/migrate-spec/SKILL.md +13 -13
  37. package/.pi/skills/model-domain/SKILL.md +5 -5
  38. package/.pi/skills/orchestrate-project/SKILL.md +2 -2
  39. package/.pi/skills/organize-workspace/SKILL.md +1 -1
  40. package/.pi/skills/plan-refactor/SKILL.md +2 -2
  41. package/.pi/skills/plan-release/SKILL.md +5 -10
  42. package/.pi/skills/plan-work/SKILL.md +15 -2
  43. package/.pi/skills/publish-package/SKILL.md +8 -8
  44. package/.pi/skills/release-branch/SKILL.md +2 -2
  45. package/.pi/skills/research-first/SKILL.md +1 -1
  46. package/.pi/skills/run-evals/SKILL.md +1 -1
  47. package/.pi/skills/security-review/SKILL.md +3 -3
  48. package/.pi/skills/seed-conventions/SKILL.md +3 -3
  49. package/.pi/skills/smoke-test/SKILL.md +5 -5
  50. package/.pi/skills/stocktake-skills/SKILL.md +1 -1
  51. package/.pi/skills/using-bigpowers/SKILL.md +1 -1
  52. package/.pi/skills/validate-contracts/SKILL.md +6 -6
  53. package/.pi/skills/verify-work/SKILL.md +1 -1
  54. package/.pi/skills/wire-ci/SKILL.md +8 -8
  55. package/.pi/skills/write-document/SKILL.md +3 -3
  56. package/CHANGELOG.md +14 -0
  57. package/README.md +1 -1
  58. package/SKILL-INDEX.md +1 -1
  59. package/allure-results/categories.json +23 -0
  60. package/allure-results/executor.json +6 -0
  61. package/allure-results/junit-results.xml +2743 -0
  62. package/package.json +4 -3
  63. package/scripts/adapters/pi.sh +4 -1
  64. package/scripts/check-skill-links.py +78 -0
  65. package/scripts/generate-allure-report.sh +146 -0
  66. package/scripts/generate-reference-tables.sh +2 -1
  67. package/scripts/lib/__pycache__/link_utils.cpython-312.pyc +0 -0
  68. package/scripts/lib/link_utils.py +49 -0
  69. package/scripts/lib/srp-engine.py +86 -1
  70. package/scripts/record-cycle-time.sh +28 -0
  71. package/scripts/sync-status-from-epics.sh +247 -24
  72. package/scripts/validate-skill-catalog.sh +1 -1
  73. package/skills/audit-code/SKILL.md +1 -1
  74. package/skills/build-epic/SKILL.md +10 -0
  75. package/skills/craft-skill/SKILL.md +2 -2
  76. package/skills/elaborate-spec/SKILL.md +1 -1
  77. package/skills/evolve-skill/REFERENCE.md +1 -1
  78. package/skills/generate-allure-report/REFERENCE.md +243 -0
  79. package/skills/generate-allure-report/SKILL.md +40 -0
  80. package/skills/grill-me/REFERENCE.md +1 -1
  81. package/skills/guard-git/SKILL.md +1 -1
  82. package/skills/harden-vps/REFERENCE.md +179 -0
  83. package/skills/harden-vps/SKILL.md +107 -0
  84. package/skills/investigate-bug/SKILL.md +2 -2
  85. package/skills/model-domain/CONTEXT-FORMAT.md +3 -3
  86. package/skills/plan-refactor/SKILL.md +2 -2
  87. package/skills/plan-release/SKILL.md +5 -10
  88. package/skills/plan-work/REFERENCE.md +13 -0
  89. package/skills/plan-work/SKILL.md +1 -1
  90. package/skills/using-bigpowers/SKILL.md +1 -1
  91. package/skills/write-document/REFERENCE.md +2 -2
  92. package/skills-lock.json +20 -10
  93. package/tests/test_srp_engine.py +148 -0
package/.pi/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.76.3",
4
- "description": "77 skills — 73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
3
+ "version": "2.77.1",
4
+ "description": "79 skills — 73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "keywords": [
6
6
  "pi-package"
7
7
  ],
@@ -26,7 +26,7 @@ Apply the full checklist to churn-ranked files in descending order. Files with z
26
26
  - Default: full checklist
27
27
  - --quick: Run only Supply Chain and Test Coverage. Use for changes under 50 LOC.
28
28
  - --gate: Non-interactive mode for automated CI gating (used by build-epic step 6). Exit with non-zero status code (`exit 1`) on ANY checklist failure; `exit 0` only if ALL items pass. Produces a compact pass/fail summary to stderr. On failure, list every ✗ item with reason.
29
- - --parallel: Run checklist sections in **isolated git worktrees** (e45s18) so concurrent checks cannot corrupt each other's working tree. See [REFERENCE.md](REFERENCE.md) or:
29
+ - --parallel: Run checklist sections in **isolated git worktrees** (e45s18) so concurrent checks cannot corrupt each other's working tree:
30
30
 
31
31
  ```bash
32
32
  bash scripts/lib/parallel-review-worktrees.sh audit-code
@@ -32,6 +32,7 @@ Orchestrates the **build** flow for a single epic: survey → plan tasks → kic
32
32
  ## Process
33
33
 
34
34
  1. Read `specs/state.yaml`, `specs/execution-status.yaml`, `specs/release-plan.yaml`, active `specs/epics/eNN-slug/epic.yaml`.
35
+ - **On story start (step 1):** Write `started_at` ISO 8601 timestamp to `execution-status.yaml` under the story's key in the `stories:` section. The `bp-timing.sh` script already tracks skill-level timings — this is story-level.
35
36
  2. **Step 0 — Threat Model:** Run `security-review` against the epic's scope (read from the epic capsule). Output `specs/security/epics/<epic-id>/THREAT_MODEL.md` with surface area, vulnerability categories, risk level, and mitigation guidance.
36
37
  3. **Assess Impact (Step 2):** Before writing tasks, run `assess-impact --lightweight` on the proposed change. If the risk score exceeds 7, gate — require a `grill-me` session. Write the impact report to `specs/IMPACT-<epic>-<story>.md`. For net-new code with no existing dependents, skip.
37
38
  4. **BCP Tracking (Step 2):** After `plan-work` completes, read the `bcps:` count (Business Complexity Points story size) from the epic capsule and carry it into `state.yaml` as `epic_cycle.story_bcps = N`.
@@ -40,6 +41,15 @@ Orchestrates the **build** flow for a single epic: survey → plan tasks → kic
40
41
  6. Run **only the current step** (resume mode) unless user asked for full auto-run.
41
42
  7. After step verify passes, increment `epic_cycle.step` in `state.yaml` (or `bash scripts/bp-yaml-set.sh` if available).
42
43
  8. On story complete, set `execution-status.yaml` story key to `done`; run `bash scripts/sync-status-from-epics.sh`.
44
+ - **On story complete (step 8):** Write `completed_at` ISO 8601 timestamp to `execution-status.yaml` under the same story key. Format:
45
+
46
+ ```yaml
47
+ stories:
48
+ e01s01:
49
+ status: done
50
+ started_at: "2026-07-12T16:00:00-03:00"
51
+ completed_at: "2026-07-12T18:45:00-03:00"
52
+ ```
43
53
  9. **Traceability refresh:** Before step 8 (release-branch), run `bash scripts/trace-stories.sh` to regenerate `specs/traceability-matrix.json`, `specs/TRACEABILITY_LATEST.md`, and the `specs/codebase-wiki/` OKF bundle. Surface dark/orphan/stale findings for the just-built epic in your verify summary. If `scripts/trace-stories.sh` is missing or fails, note "trace skipped" and continue — trace failure must be visible, not silent (blocking is gate-trace's job, e38s06).
44
54
 
45
55
  9b. **OKF wiki refresh (e39s08):** Before step 8, run maintain-wiki INGEST to refresh the OKF wiki bundle:
@@ -29,7 +29,7 @@ Move process detail into the SKILL.md body or REFERENCE.md — never into `descr
29
29
  - Any reference materials to include?
30
30
  - What specs/ output does it produce (if any)?
31
31
 
32
- 2. **Verify Principles** — Ensure the skill aligns with [PRINCIPLES.md](../docs/PRINCIPLES.md):
32
+ 2. **Verify Principles** — Ensure the skill aligns with [PRINCIPLES.md](https://github.com/danielvm-git/bigpowers/blob/main/docs/PRINCIPLES.md):
33
33
  - Is it atomic (verb-noun)?
34
34
  - Is it "deep" (simple interface, complex internal logic)?
35
35
  - Does it include Hard Gates?
@@ -42,7 +42,7 @@ Move process detail into the SKILL.md body or REFERENCE.md — never into `descr
42
42
 
43
43
  **Auto-skill from library README:** When user provides a library README or API docs URL, extract: triggers, HARD GATEs, verify commands, specs/ output — draft SKILL.md without inventing APIs not in the source.
44
44
 
45
- 4. Add `model:` frontmatter (`haiku` | `sonnet` | `opus`) per [model-profiles.md](../docs/references/model-profiles.md).
45
+ 4. Add `model:` frontmatter (`haiku` | `sonnet` | `opus`) per [model-profiles.md](https://github.com/danielvm-git/bigpowers/blob/main/docs/references/model-profiles.md).
46
46
 
47
47
  > **STREAM CONTINUITY** — When writing file content, output in continuous chunks of ~200 lines. Do not pause. Continue immediately until complete. If you need time, emit a placeholder comment rather than going silent.
48
48
 
@@ -62,7 +62,7 @@ Once the user has answered the main questions, probe for assumptions:
62
62
 
63
63
  ### 4. Synthesize and confirm
64
64
 
65
- Summarize your understanding in 3–5 bullet points aligned with [countable-story-format.md](file:///Users/danielvm/Developer/bigpowers/countable-story-format.md):
65
+ Summarize your understanding in 3–5 bullet points aligned with [countable-story-format.md](https://github.com/danielvm-git/bigpowers/blob/main/docs/countable-story-format.md):
66
66
  - The problem (feeds into §1 Business narrative)
67
67
  - The solution and main flow (feeds into §5)
68
68
  - The key constraints and alternative flows (feeds into §6)
@@ -51,4 +51,4 @@ See [REFERENCE.md](REFERENCE.md) for ADR template.
51
51
  **Evidence:** path/to/benchmark-report.md
52
52
  ```
53
53
 
54
- Benchmark repo: `/Users/danielvm/Developer/bigpowers-benchmark/`
54
+ Benchmark repo: `bigpowers-benchmark` — resolve the local clone on this machine (e.g. `gh repo clone danielvm-git/bigpowers-benchmark` if absent); never assume a hard-coded absolute path.
@@ -0,0 +1,284 @@
1
+ ---
2
+ name: generate-allure-report
3
+ description: "Generate Allure-ready reports from bigpowers YAML metadata. Reads execution-status.yaml, release-plan.yaml, epic capsules, task YAMLs, cycle-times.yaml, and bug registry to produce allure-results/junit-results.xml, categories.json, and executor.json. Use when preparing progress dashboards, integrating with Allure TestOps, or generating CI reports."
4
+ ---
5
+
6
+ # Generate Allure Report
7
+
8
+ Generate Allure TestOps-compatible reports from bigpowers project metadata. Produces JUnit XML for story-level test results, custom categories for filtering, and executor metadata — all in the `allure-results/` directory.
9
+
10
+ ## Quick Start
11
+
12
+ ```bash
13
+ bash scripts/generate-allure-report.sh
14
+ ```
15
+
16
+ ## What It Produces
17
+
18
+ Three files in `allure-results/`:
19
+
20
+ | File | Description |
21
+ |------|-------------|
22
+ | `junit-results.xml` | One `<testcase>` per story with `<properties>` for risk, security, WSJF, tier, wave, and status. Incomplete stories get a `<failure>` element. |
23
+ | `categories.json` | Custom Allure categories for filtering by epic, risk level (P0), and security reviews. |
24
+ | `executor.json` | Build metadata — name, type, version from release-plan.yaml, build order. |
25
+
26
+ ## Data Sources
27
+
28
+ See [REFERENCE.md](REFERENCE.md)
29
+
30
+ ## Verify
31
+
32
+ ```bash
33
+ test -f allure-results/junit-results.xml && test -f allure-results/categories.json && test -f allure-results/executor.json
34
+ ```
35
+
36
+ ## Handoff
37
+
38
+ - next_skill: null (terminal skill — no downstream workflow step)
39
+
40
+ ---
41
+
42
+ # generate-allure-report — Reference
43
+
44
+ ## Data Sources
45
+
46
+ The script reads five YAML sources from the project:
47
+
48
+ | Source | Path | Fields Used |
49
+ |--------|------|-------------|
50
+ | Execution status | `specs/execution-status.yaml` | `epics`, `stories`, `development_status` |
51
+ | Release plan | `specs/release-plan.yaml` | `release.version`, `release.status`, `bugs` summary |
52
+ | Epic capsules | `specs/epics/**/epic.yaml` + `-tasks.yaml` | Epic metadata, task pass/fail counts |
53
+ | Cycle times | `specs/metrics/cycle-times.yaml` | Story-level `cycle_minutes`, `bcp_per_hour`, `source` |
54
+ | Bug registry | `specs/bugs/registry.yaml` | Bug counts by status and severity |
55
+
56
+ ## Script Body
57
+
58
+ `scripts/generate-allure-report.sh`:
59
+
60
+ ```bash
61
+ #!/usr/bin/env bash
62
+ set -euo pipefail
63
+ source "$(dirname "${BASH_SOURCE[0]}")/lib/python-env.sh"
64
+ ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || ROOT="$(dirname "${BASH_SOURCE[0]}")/.."
65
+
66
+ mkdir -p "$ROOT/allure-results"
67
+
68
+ $PYTHON - "$ROOT" <<'PY'
69
+ import json
70
+ import sys
71
+ import xml.etree.ElementTree as ET
72
+ from pathlib import Path
73
+
74
+ root = Path(sys.argv[1])
75
+ out = root / "allure-results"
76
+
77
+ # 1. Read execution-status.yaml
78
+ exec_status_file = root / "specs" / "execution-status.yaml"
79
+ release_plan_file = root / "specs" / "release-plan.yaml"
80
+ cycle_times_file = root / "specs" / "metrics" / "cycle-times.yaml"
81
+ bugs_registry_file = root / "specs" / "bugs" / "registry.yaml"
82
+
83
+ sys.path.insert(0, str(root / "scripts" / "lib"))
84
+ from simple_yaml import parse_simple_yaml
85
+
86
+ exec_status = parse_simple_yaml(exec_status_file.read_text()) if exec_status_file.exists() else {}
87
+ release_plan = parse_simple_yaml(release_plan_file.read_text()) if release_plan_file.exists() else {}
88
+ cycle_times = parse_simple_yaml(cycle_times_file.read_text()) if cycle_times_file.exists() else {"stories": []}
89
+ bugs_registry = parse_simple_yaml(bugs_registry_file.read_text()) if bugs_registry_file.exists() else {"bugs": []}
90
+
91
+ # Build cycle-times lookup
92
+ ct_lookup = {}
93
+ for ct in cycle_times.get("stories", []):
94
+ if isinstance(ct, dict):
95
+ ct_lookup[ct.get("id", "")] = ct
96
+
97
+ # 2. Build JUnit XML
98
+ stories = exec_status.get("stories", {})
99
+
100
+ # Counts for testsuite attributes
101
+ total_stories = len(stories)
102
+ incomplete = sum(1 for s in stories.values() if isinstance(s, dict) and s.get("status") != "done")
103
+
104
+ testsuite = ET.Element("testsuite", {
105
+ "name": "bigpowers-epic-progress",
106
+ "tests": str(total_stories),
107
+ "failures": str(incomplete),
108
+ "errors": "0",
109
+ "skipped": "0",
110
+ })
111
+
112
+ for story_id in sorted(stories.keys()):
113
+ story = stories[story_id]
114
+ if not isinstance(story, dict):
115
+ continue
116
+
117
+ epic_id = story.get("epic", "unknown")
118
+ title = story.get("title", story_id)
119
+ bcps = story.get("bcps", 0)
120
+ status = story.get("status", "backlog")
121
+ risk_max = story.get("risk_max", "none")
122
+ security_max = story.get("security_max", "none")
123
+
124
+ # Enrich with cycle-times data
125
+ ct_data = ct_lookup.get(story_id, {})
126
+ cycle_minutes = ct_data.get("cycle_minutes", 0)
127
+ bcp_per_hour = ct_data.get("bcp_per_hour", 0)
128
+
129
+ # Time: cycle_minutes * 60 for seconds in Allure display
130
+ time_seconds = cycle_minutes * 60.0 if cycle_minutes else 0.0
131
+
132
+ testcase = ET.SubElement(testsuite, "testcase", {
133
+ "classname": epic_id,
134
+ "name": f"{story_id}: {title}",
135
+ "time": str(round(time_seconds, 3)),
136
+ })
137
+
138
+ props = ET.SubElement(testcase, "properties")
139
+ ET.SubElement(props, "property", {"name": "risk", "value": risk_max})
140
+ ET.SubElement(props, "property", {"name": "security", "value": security_max})
141
+ ET.SubElement(props, "property", {"name": "bcps", "value": str(bcps)})
142
+ ET.SubElement(props, "property", {"name": "status", "value": status})
143
+ ET.SubElement(props, "property", {"name": "bcp_per_hour", "value": str(bcp_per_hour)})
144
+ ET.SubElement(props, "property", {"name": "lead_time_minutes", "value": str(cycle_minutes)})
145
+
146
+ if status != "done":
147
+ ET.SubElement(testcase, "failure", {
148
+ "message": f"Story {story_id} is {status} [risk={risk_max}, security={security_max}]",
149
+ "type": "StoryIncomplete"
150
+ })
151
+
152
+ tree = ET.ElementTree(testsuite)
153
+ ET.indent(tree, space=" ")
154
+ tree.write(str(out / "junit-results.xml"), encoding="utf-8", xml_declaration=True)
155
+
156
+ # 3. Build categories.json
157
+ epics = exec_status.get("epics", {})
158
+ categories = []
159
+
160
+ for epic_id in sorted(epics.keys()):
161
+ epic = epics[epic_id]
162
+ if isinstance(epic, dict) and epic.get("status") != "done":
163
+ categories.append({
164
+ "name": f"Epic: {epic.get('title', epic_id)}",
165
+ "matchedStatuses": ["failed"],
166
+ "messageRegex": f".*{epic_id}:.*"
167
+ })
168
+
169
+ categories.append({
170
+ "name": "P0 Risk",
171
+ "matchedStatuses": ["failed"],
172
+ "messageRegex": ".*risk.*P0.*"
173
+ })
174
+ categories.append({
175
+ "name": "Security Review",
176
+ "matchedStatuses": ["failed"],
177
+ "messageRegex": ".*security.*(?:medium|high).*"
178
+ })
179
+
180
+ # Add bug-based categories
181
+ bug_list = bugs_registry.get("bugs", [])
182
+ bug_count = len(bug_list) if isinstance(bug_list, list) else 0
183
+ open_bugs = sum(1 for b in bug_list if isinstance(b, dict) and b.get("status") not in ("fixed", "closed", None))
184
+ if open_bugs > 0:
185
+ categories.append({
186
+ "name": "Open Bugs",
187
+ "matchedStatuses": ["failed"],
188
+ "messageRegex": ".*Bug.*"
189
+ })
190
+
191
+ (out / "categories.json").write_text(json.dumps(categories, indent=2))
192
+
193
+ # 4. Build executor.json
194
+ rl = release_plan.get("release", {}) if isinstance(release_plan.get("release"), dict) else {}
195
+ executor = {
196
+ "name": "bigpowers",
197
+ "type": "bigpowers",
198
+ "buildName": rl.get("version", "unknown") if isinstance(rl, dict) else "unknown",
199
+ "buildOrder": len(exec_status.get("development_status", {})),
200
+ }
201
+ (out / "executor.json").write_text(json.dumps(executor, indent=2))
202
+
203
+ # Summary
204
+ epic_count = len([e for e in epics.values() if isinstance(e, dict) and e.get("status") == "done"])
205
+ total_epics = len(epics)
206
+ print(f"generate-allure-report: {total_stories} stories, {epic_count}/{total_epics} epics done, {bug_count} bugs")
207
+ print(f" -> {out}/junit-results.xml")
208
+ print(f" -> {out}/categories.json")
209
+ print(f" -> {out}/executor.json")
210
+ PY
211
+ ```
212
+
213
+ ## JUnit XML Schema
214
+
215
+ ```xml
216
+ <?xml version="1.0" encoding="utf-8"?>
217
+ <testsuite name="bigpowers-epic-progress" tests="N" failures="F" errors="0" skipped="0">
218
+ <testcase classname="e01" name="e01s01: Security slopcheck tags" time="0.75">
219
+ <properties>
220
+ <property name="risk" value="none"/>
221
+ <property name="security" value="none"/>
222
+ <property name="bcps" value="1"/>
223
+ <property name="status" value="done"/>
224
+ <property name="bcp_per_hour" value="1.3"/>
225
+ <property name="lead_time_minutes" value="45"/>
226
+ </properties>
227
+ </testcase>
228
+ <testcase classname="e01" name="e01s99: Some incomplete story" time="0.0">
229
+ <properties>...</properties>
230
+ <failure message="Story e01s99 is backlog [risk=P0, security=high]" type="StoryIncomplete"/>
231
+ </testcase>
232
+ </testsuite>
233
+ ```
234
+
235
+ ## Categories JSON Schema
236
+
237
+ ```json
238
+ [
239
+ {
240
+ "name": "Epic: Quality Core - Skill Hardening",
241
+ "matchedStatuses": ["failed"],
242
+ "messageRegex": ".*e45:.*"
243
+ },
244
+ {
245
+ "name": "P0 Risk",
246
+ "matchedStatuses": ["failed"],
247
+ "messageRegex": ".*risk.*P0.*"
248
+ },
249
+ {
250
+ "name": "Security Review",
251
+ "matchedStatuses": ["failed"],
252
+ "messageRegex": ".*security.*(?:medium|high).*"
253
+ }
254
+ ]
255
+ ```
256
+
257
+ ## Executor JSON Schema
258
+
259
+ ```json
260
+ {
261
+ "name": "bigpowers",
262
+ "type": "bigpowers",
263
+ "buildName": "2.76.2",
264
+ "buildOrder": 400
265
+ }
266
+ ```
267
+
268
+ ## Example Usage
269
+
270
+ ```bash
271
+ # Generate reports
272
+ bash scripts/generate-allure-report.sh
273
+
274
+ # Verify output
275
+ test -f allure-results/junit-results.xml && echo "JUnit OK"
276
+ test -f allure-results/categories.json && echo "Categories OK"
277
+ test -f allure-results/executor.json && echo "Executor OK"
278
+
279
+ # Serve with Allure
280
+ allure serve allure-results/
281
+
282
+ # Or open the Allure TestOps UI
283
+ allure open allure-results/
284
+ ```
@@ -75,7 +75,7 @@ Ask one question at a time. For each challenge, cite the specific URL and sectio
75
75
 
76
76
  When an assumption doesn't match the docs:
77
77
 
78
- > "Your plan uses `library.doThing(a, b)` but the [docs](URL) show the signature is `doThing(config: {a, b})` with a config object. This will fail at runtime."
78
+ > "Your plan uses `library.doThing(a, b)` but the [docs](https://example.com/api-reference) show the signature is `doThing(config: {a, b})` with a config object. This will fail at runtime."
79
79
 
80
80
  Document each discrepancy clearly.
81
81
 
@@ -20,7 +20,7 @@ Installs a shared hook that blocks destructive git operations and enforces workf
20
20
  ## Quick start
21
21
 
22
22
  1. **Scope**: ask project-only vs global (paths differ per product).
23
- 2. **Copy the hook bundle** from the root [hooks/](hooks/) directory to the client's hooks directory.
23
+ 2. **Write the hook bundle** from [REFERENCE.md](REFERENCE.md) into the client's hooks directory.
24
24
  3. **Run `chmod +x`** on `pre-tool-use.sh`.
25
25
  4. **Merge** the hook snippet from [REFERENCE.md](REFERENCE.md) into the right settings file — do not wipe unrelated keys.
26
26
  5. **Verify** with the tests in [REFERENCE.md](REFERENCE.md).
@@ -0,0 +1,287 @@
1
+ ---
2
+ name: harden-vps
3
+ description: "Harden a production Linux VPS for BigBase across three layers — BigBase app (systemd hardening, monitoring alerts, backup automation), Ubuntu OS (UFW firewall, fail2ban SSH, unattended-upgrades, SSH hardening), and Contabo VPS (health checks, daily backups, monthly snapshots). Use when the user wants to secure a production server, harden a VPS, audit server security, or mentions production hardening, VPS security, or harden the server."
4
+ ---
5
+
6
+ # Harden VPS
7
+
8
+ Three-layer production hardening for BigBase on Contabo VPS. Each layer independently verifiable. Apply OS first (firewall blocks attacks immediately), then BigBase (alerts + backups), then Contabo (snapshots). See [REFERENCE.md](REFERENCE.md) for full script bodies, systemd unit template, and gotchas.
9
+
10
+ ## Quick start
11
+
12
+ SSH as root into the VPS. Find credentials in the Contabo Customer Control Panel.
13
+
14
+ > **HARD GATE** — Run `ufw status` first. No firewall = layer 1 takes priority over everything.
15
+
16
+ ## Layer 1 — Ubuntu OS
17
+
18
+ ```bash
19
+ # UFW
20
+ ufw default deny incoming && ufw default allow outgoing
21
+ ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable
22
+ # → verify: ufw status | grep -q active
23
+
24
+ # fail2ban
25
+ apt install -y fail2ban
26
+ # Configure /etc/fail2ban/jail.local: sshd, maxretry=3, bantime=3600, findtime=600
27
+ systemctl restart fail2ban
28
+ # → verify: fail2ban-client status sshd
29
+
30
+ # unattended-upgrades
31
+ apt install -y unattended-upgrades && dpkg-reconfigure -plow unattended-upgrades
32
+ # → verify: systemctl is-active unattended-upgrades | grep -q active
33
+
34
+ # SSH: PermitRootLogin no, PasswordAuthentication no, PubkeyAuthentication yes
35
+ # → verify: sshd -T | grep -E 'permitrootlogin no|passwordauthentication no'
36
+
37
+ # Deploy healthcheck.sh → /opt/bigbase/scripts/healthcheck.sh
38
+ # Crontab: */5 * * * * /opt/bigbase/scripts/healthcheck.sh
39
+ ```
40
+
41
+ ## Layer 2 — BigBase application
42
+
43
+ ```bash
44
+ # systemd: User=bigbase, NoNewPrivileges=yes, ProtectSystem=full,
45
+ # ProtectKernelTunables=yes, ProtectKernelModules=yes,
46
+ # ProtectControlGroups=yes, RestrictAddressFamilies=AF_INET AF_INET6,
47
+ # RestrictRealtime=yes, PrivateTmp=yes, LimitNOFILE=65536
48
+ # → verify: systemctl show bigbase -p NoNewPrivileges -p ProtectSystem -p User
49
+
50
+ # Alerts (BigBase requires auth; insert via SQLite)
51
+ sqlite3 /opt/bigbase/data/bigbase.db "
52
+ INSERT INTO monitoring_alerts (id,name,metric,threshold,operator,enabled,duration_seconds)
53
+ VALUES ('a1','Disk >80%','disk_used_percent',80,'gt',1,300);
54
+ INSERT INTO monitoring_alerts (id,name,metric,threshold,operator,enabled,duration_seconds)
55
+ VALUES ('a2','CPU >90%','cpu_percent',90,'gt',1,60);
56
+ INSERT INTO monitoring_alerts (id,name,metric,threshold,operator,enabled,duration_seconds)
57
+ VALUES ('a3','RAM >85%','mem_used_percent',85,'gt',1,120);
58
+ "
59
+ systemctl restart bigbase
60
+
61
+ # Backup crontab (root):
62
+ # 0 2 * * * cp /opt/bigbase/data/bigbase.db /backup/bigbase-$(date +\%Y\%m\%d).db
63
+ # 0 3 * * * find /backup/ -name "bigbase-*.db" -mtime +90 -delete
64
+ ```
65
+
66
+ ## Layer 3 — Contabo VPS
67
+
68
+ ```bash
69
+ # cntb CLI
70
+ curl -sL "$(curl -sL https://api.github.com/repos/contabo/cntb/releases/latest \
71
+ | grep browser_download_url.*linux_amd64.tar.gz | head -1 | cut -d'"' -f4)" \
72
+ | tar xz -C /usr/local/bin
73
+
74
+ # Snapshot script → /opt/bigbase/scripts/contabo-snapshot.sh (reads from /opt/bigbase/.env)
75
+ # Credentials as env vars in /opt/bigbase/.env (deployed by GitHub Actions):
76
+ # CONTABO_CLIENT_ID, CONTABO_CLIENT_SECRET, CONTABO_API_USER, CONTABO_API_PASSWORD
77
+ # Crontab: 0 4 1 * * /opt/bigbase/scripts/contabo-snapshot.sh
78
+
79
+ # > HARD GATE — Snapshot cron silently fails until env vars are set in .env.
80
+ # Credentials source: Contabo Customer Panel → API Details.
81
+ # Local dev: add to .envrc. Production: GitHub Secrets → deploy → /opt/bigbase/.env
82
+ ```
83
+
84
+ ## CRITICAL GOTCHAS
85
+
86
+ 1. **Shell escaping in Orca terminals:** `$VAR`, `$(…)`, and `%` get eaten by the local shell. Always use base64: `echo '<base64>' | base64 -d > script.sh`
87
+ 2. **Crontab `%`:** cron interprets `%` as newline. Escape as `\%` in `$(date +\%Y\%m\%d)`
88
+ 3. **fail2ban exit 255:** means a jail references a missing log file. Remove the broken jail, restart.
89
+ 4. **BigBase alerts need auth:** POST to `/api/monitoring/alerts` requires Bearer token. Workaround: insert directly into SQLite, then restart BigBase.
90
+
91
+ ## Verify all 8 gates
92
+
93
+ ```bash
94
+ ufw status|grep -q active||echo FAIL:ufw
95
+ fail2ban-client status sshd>/dev/null 2>&1||echo FAIL:fail2ban
96
+ systemctl is-active unattended-upgrades|grep -q active||echo FAIL:unattended
97
+ sshd -T|grep -q 'permitrootlogin no'||echo FAIL:sshd
98
+ systemctl show bigbase -p NoNewPrivileges|grep -q yes||echo FAIL:systemd
99
+ systemctl is-active bigbase|grep -q active||echo FAIL:bigbase
100
+ sqlite3 /opt/bigbase/data/bigbase.db "SELECT count(*) FROM monitoring_alerts"|grep -q 3||echo FAIL:alerts
101
+ crontab -l|grep -q healthcheck&&crontab -l|grep -q bigbase.db&&crontab -l|grep -q contabo-snapshot||echo FAIL:crontab
102
+ echo ALL 8 GATES PASSED
103
+ ```
104
+
105
+ → verify: run the 8-gate one-liner on the VPS.
106
+
107
+ ---
108
+
109
+ # Harden VPS — Reference
110
+
111
+ ## Health check script
112
+
113
+ Deploy to `/opt/bigbase/scripts/healthcheck.sh`:
114
+
115
+ ```bash
116
+ #!/bin/bash
117
+ LOG=/var/log/bigbase/health.log
118
+ mkdir -p /var/log/bigbase
119
+ DISK=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
120
+ RAM=$(free | awk '/Mem:/ {printf "%.0f", $3/$2*100}')
121
+ NOW=$(date -Iseconds)
122
+ [ "$DISK" -gt 85 ] && echo "$NOW ALERT: Disk ${DISK}%" >> "$LOG"
123
+ [ "$RAM" -gt 90 ] && echo "$NOW ALERT: RAM ${RAM}%" >> "$LOG"
124
+ systemctl is-active --quiet bigbase || { echo "$NOW ALERT: BigBase DOWN" >> "$LOG"; systemctl restart bigbase; }
125
+ [ -f /var/run/reboot-required ] && echo "$NOW WARN: kernel reboot pending" >> "$LOG"
126
+ ```
127
+
128
+ Make executable: `chmod +x /opt/bigbase/scripts/healthcheck.sh`
129
+
130
+ ## BigBase systemd unit
131
+
132
+ Full hardened unit at `/etc/systemd/system/bigbase.service`:
133
+
134
+ ```ini
135
+ [Unit]
136
+ Description=BigBase BaaS Platform
137
+ Documentation=https://github.com/danielvm-git/bigbase
138
+ After=network.target caddy.service
139
+ Wants=caddy.service
140
+
141
+ [Service]
142
+ Type=simple
143
+ User=bigbase
144
+ Group=bigbase
145
+ WorkingDirectory=/opt/bigbase
146
+ ExecStart=/opt/bigbase/bin/bigbase serve \
147
+ --port 8080 \
148
+ --db /opt/bigbase/data/bigbase.db \
149
+ --sites-domain <your-domain.example.com>
150
+ EnvironmentFile=-/opt/bigbase/.env
151
+ Environment=BIGBASE_HOME=/opt/bigbase
152
+ Environment=HOME=/opt/bigbase
153
+ Environment=NPM_CONFIG_CACHE=/opt/bigbase/.npm
154
+ Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
155
+ Restart=always
156
+ RestartSec=5
157
+ StartLimitIntervalSec=60
158
+ StartLimitBurst=3
159
+ TimeoutStopSec=30
160
+ KillSignal=SIGTERM
161
+ NoNewPrivileges=yes
162
+ PrivateTmp=yes
163
+ ProtectSystem=full
164
+ ProtectHome=yes
165
+ ProtectKernelTunables=yes
166
+ ProtectKernelModules=yes
167
+ ProtectControlGroups=yes
168
+ RestrictAddressFamilies=AF_INET AF_INET6
169
+ RestrictRealtime=yes
170
+ ReadWritePaths=/opt/bigbase/data
171
+ ReadWritePaths=/opt/bigbase/backups
172
+ ReadWritePaths=/opt/bigbase/secrets
173
+ ReadWritePaths=/opt/bigbase/.npm
174
+ ReadWritePaths=/opt/bigbase/logs
175
+ LimitNOFILE=65536
176
+
177
+ [Install]
178
+ WantedBy=multi-user.target
179
+ ```
180
+
181
+ ## fail2ban jail.local
182
+
183
+ ```ini
184
+ [sshd]
185
+ enabled = true
186
+ port = ssh
187
+ filter = sshd
188
+ logpath = /var/log/auth.log
189
+ maxretry = 3
190
+ bantime = 3600
191
+ findtime = 600
192
+ ```
193
+
194
+ Note: BigBase auth jail deferred — BigBase logs to journald, not a file. To enable, use `backend = systemd` with a journald filter.
195
+
196
+ ## contabo-snapshot.sh
197
+
198
+ Deploy to `/opt/bigbase/scripts/contabo-snapshot.sh`. Reads credentials from `/opt/bigbase/.env` (same file used by BigBase systemd unit):
199
+
200
+ ```bash
201
+ #!/bin/bash
202
+ set -e
203
+ LOG=/var/log/bigbase/snapshot.log
204
+ ENVFILE=/opt/bigbase/.env
205
+ INSTANCE_ID=<your-contabo-instance-id>
206
+
207
+ [ -f "$ENVFILE" ] || { echo "$(date -Iseconds) ERROR: $ENVFILE missing" >> "$LOG"; exit 1; }
208
+ set -a; source "$ENVFILE"; set +a
209
+
210
+ [ -z "$CONTABO_CLIENT_ID" ] && { echo "$(date -Iseconds) ERROR: CONTABO_CLIENT_ID not set" >> "$LOG"; exit 1; }
211
+
212
+ TOKEN=$(curl -s -d "client_id=$CONTABO_CLIENT_ID" \
213
+ -d "client_secret=$CONTABO_CLIENT_SECRET" \
214
+ --data-urlencode "username=$CONTABO_API_USER" \
215
+ --data-urlencode "password=$CONTABO_API_PASSWORD" \
216
+ -d 'grant_type=password' \
217
+ 'https://auth.contabo.com/auth/realms/contabo/protocol/openid-connect/token' \
218
+ | jq -r '.access_token')
219
+
220
+ [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ] && { echo "$(date -Iseconds) ERROR: auth failed" >> "$LOG"; exit 1; }
221
+
222
+ curl -s -X POST \
223
+ -H "Authorization: Bearer $TOKEN" \
224
+ -H "Content-Type: application/json" \
225
+ -H "x-request-id: $(uuidgen 2>/dev/null || echo $RANDOM)" \
226
+ "https://api.contabo.com/v1/compute/instances/${INSTANCE_ID}/snapshots" \
227
+ | tee -a "$LOG"
228
+
229
+ echo >> "$LOG"
230
+ echo "$(date -Iseconds) Snapshot requested for $INSTANCE_ID" >> "$LOG"
231
+ ```
232
+
233
+ ## Contabo credentials
234
+
235
+ Add to `/opt/bigbase/.env` (same file used by BigBase systemd unit, deployed by GitHub Actions):
236
+
237
+ ```
238
+ CONTABO_CLIENT_ID=
239
+ CONTABO_CLIENT_SECRET=
240
+ CONTABO_API_USER=
241
+ CONTABO_API_PASSWORD=
242
+ ```
243
+
244
+ Source: Contabo Customer Control Panel → API Details. ClientId and ClientSecret are generated there. API User is your email. API Password is set separately in the panel.
245
+
246
+ **Pipeline:** GitHub Secrets → deploy workflow → `/opt/bigbase/.env` on VPS. For local dev (`cntb get instances`), add to `.envrc`.
247
+
248
+ ## Contabo instance info template
249
+
250
+ Fill in your instance details from the Contabo Customer Control Panel:
251
+
252
+ ```
253
+ IP: <your-instance-ip>
254
+ IPv6: <your-instance-ipv6>
255
+ Region: <your-region>
256
+ OS: <your-os-version>
257
+ Disk: <your-disk-size>
258
+ Default user: root
259
+ Customer ID: <your-customer-id>
260
+ ```
261
+
262
+ ## BigBase monitoring alert SQL
263
+
264
+ ```sql
265
+ INSERT INTO monitoring_alerts (id, name, metric, threshold, operator, enabled, duration_seconds)
266
+ VALUES ('alert-001', 'VPS Disk above 80%', 'disk_used_percent', 80, 'gt', 1, 300);
267
+
268
+ INSERT INTO monitoring_alerts (id, name, metric, threshold, operator, enabled, duration_seconds)
269
+ VALUES ('alert-002', 'VPS CPU above 90%', 'cpu_percent', 90, 'gt', 1, 60);
270
+
271
+ INSERT INTO monitoring_alerts (id, name, metric, threshold, operator, enabled, duration_seconds)
272
+ VALUES ('alert-003', 'VPS RAM above 85%', 'mem_used_percent', 85, 'gt', 1, 120);
273
+ ```
274
+
275
+ Alerts are loaded at BigBase startup. Restart with `systemctl restart bigbase` after inserting.
276
+
277
+ ## Base64 encoding workaround
278
+
279
+ When sending scripts through Orca terminal `--text`, the local bash shell interprets `$`, `(`, and `%`. Encode locally and decode remotely:
280
+
281
+ ```bash
282
+ # Local
283
+ cat script.sh | base64
284
+
285
+ # Remote terminal
286
+ echo '<base64-output>' | base64 -d > script.sh
287
+ ```