@nomos-arc/arc 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/.claude/settings.local.json +10 -0
- package/.nomos-config.json +5 -0
- package/CLAUDE.md +108 -0
- package/LICENSE +190 -0
- package/README.md +569 -0
- package/dist/cli.js +21120 -0
- package/docs/auth/googel_plan.yaml +1093 -0
- package/docs/auth/google_task.md +235 -0
- package/docs/auth/hardened_blueprint.yaml +1658 -0
- package/docs/auth/red_team_report.yaml +336 -0
- package/docs/auth/session_state.yaml +162 -0
- package/docs/certificate/cer_enhance_plan.md +605 -0
- package/docs/certificate/certificate_report.md +338 -0
- package/docs/dev_overview.md +419 -0
- package/docs/feature_assessment.md +156 -0
- package/docs/how_it_works.md +78 -0
- package/docs/infrastructure/map.md +867 -0
- package/docs/init/master_plan.md +3581 -0
- package/docs/init/red_team_report.md +215 -0
- package/docs/init/report_phase_1a.md +304 -0
- package/docs/integrity-gate/enhance_drift.md +703 -0
- package/docs/integrity-gate/overview.md +108 -0
- package/docs/management/manger-task.md +99 -0
- package/docs/management/scafffold.md +76 -0
- package/docs/map/ATOMIC_BLUEPRINT.md +1349 -0
- package/docs/map/RED_TEAM_REPORT.md +159 -0
- package/docs/map/map_task.md +147 -0
- package/docs/map/semantic_graph_task.md +792 -0
- package/docs/map/semantic_master_plan.md +705 -0
- package/docs/phase7/TEAM_RED.md +249 -0
- package/docs/phase7/plan.md +1682 -0
- package/docs/phase7/task.md +275 -0
- package/docs/prompts/USAGE.md +312 -0
- package/docs/prompts/architect.md +165 -0
- package/docs/prompts/executer.md +190 -0
- package/docs/prompts/hardener.md +190 -0
- package/docs/prompts/red_team.md +146 -0
- package/docs/verification/goveranance-overview.md +396 -0
- package/docs/verification/governance-overview.md +245 -0
- package/docs/verification/verification-arc-ar.md +560 -0
- package/docs/verification/verification-architecture.md +560 -0
- package/docs/very_next.md +52 -0
- package/docs/whitepaper.md +89 -0
- package/overview.md +1469 -0
- package/package.json +63 -0
- package/src/adapters/__tests__/git.test.ts +296 -0
- package/src/adapters/__tests__/stdio.test.ts +70 -0
- package/src/adapters/git.ts +226 -0
- package/src/adapters/pty.ts +159 -0
- package/src/adapters/stdio.ts +113 -0
- package/src/cli.ts +83 -0
- package/src/commands/apply.ts +47 -0
- package/src/commands/auth.ts +301 -0
- package/src/commands/certificate.ts +89 -0
- package/src/commands/discard.ts +24 -0
- package/src/commands/drift.ts +116 -0
- package/src/commands/index.ts +78 -0
- package/src/commands/init.ts +121 -0
- package/src/commands/list.ts +75 -0
- package/src/commands/map.ts +55 -0
- package/src/commands/plan.ts +30 -0
- package/src/commands/review.ts +58 -0
- package/src/commands/run.ts +63 -0
- package/src/commands/search.ts +147 -0
- package/src/commands/show.ts +63 -0
- package/src/commands/status.ts +59 -0
- package/src/core/__tests__/budget.test.ts +213 -0
- package/src/core/__tests__/certificate.test.ts +385 -0
- package/src/core/__tests__/config.test.ts +191 -0
- package/src/core/__tests__/preflight.test.ts +24 -0
- package/src/core/__tests__/prompt.test.ts +358 -0
- package/src/core/__tests__/review.test.ts +161 -0
- package/src/core/__tests__/state.test.ts +362 -0
- package/src/core/auth/__tests__/manager.test.ts +166 -0
- package/src/core/auth/__tests__/server.test.ts +220 -0
- package/src/core/auth/gcp-projects.ts +160 -0
- package/src/core/auth/manager.ts +114 -0
- package/src/core/auth/server.ts +141 -0
- package/src/core/budget.ts +119 -0
- package/src/core/certificate.ts +502 -0
- package/src/core/config.ts +212 -0
- package/src/core/errors.ts +54 -0
- package/src/core/factory.ts +49 -0
- package/src/core/graph/__tests__/builder.test.ts +272 -0
- package/src/core/graph/__tests__/contract-writer.test.ts +175 -0
- package/src/core/graph/__tests__/enricher.test.ts +299 -0
- package/src/core/graph/__tests__/parser.test.ts +200 -0
- package/src/core/graph/__tests__/pipeline.test.ts +202 -0
- package/src/core/graph/__tests__/renderer.test.ts +128 -0
- package/src/core/graph/__tests__/resolver.test.ts +185 -0
- package/src/core/graph/__tests__/scanner.test.ts +231 -0
- package/src/core/graph/__tests__/show.test.ts +134 -0
- package/src/core/graph/builder.ts +303 -0
- package/src/core/graph/constraints.ts +94 -0
- package/src/core/graph/contract-writer.ts +93 -0
- package/src/core/graph/drift/__tests__/classifier.test.ts +215 -0
- package/src/core/graph/drift/__tests__/comparator.test.ts +335 -0
- package/src/core/graph/drift/__tests__/drift.test.ts +453 -0
- package/src/core/graph/drift/__tests__/reporter.test.ts +203 -0
- package/src/core/graph/drift/classifier.ts +165 -0
- package/src/core/graph/drift/comparator.ts +205 -0
- package/src/core/graph/drift/reporter.ts +77 -0
- package/src/core/graph/enricher.ts +251 -0
- package/src/core/graph/grammar-paths.ts +30 -0
- package/src/core/graph/html-template.ts +493 -0
- package/src/core/graph/map-schema.ts +137 -0
- package/src/core/graph/parser.ts +336 -0
- package/src/core/graph/pipeline.ts +209 -0
- package/src/core/graph/renderer.ts +92 -0
- package/src/core/graph/resolver.ts +195 -0
- package/src/core/graph/scanner.ts +145 -0
- package/src/core/logger.ts +46 -0
- package/src/core/orchestrator.ts +792 -0
- package/src/core/plan-file-manager.ts +66 -0
- package/src/core/preflight.ts +64 -0
- package/src/core/prompt.ts +173 -0
- package/src/core/review.ts +95 -0
- package/src/core/state.ts +294 -0
- package/src/core/worktree-coordinator.ts +77 -0
- package/src/search/__tests__/chunk-extractor.test.ts +339 -0
- package/src/search/__tests__/embedder-auth.test.ts +124 -0
- package/src/search/__tests__/embedder.test.ts +267 -0
- package/src/search/__tests__/graph-enricher.test.ts +178 -0
- package/src/search/__tests__/indexer.test.ts +518 -0
- package/src/search/__tests__/integration.test.ts +649 -0
- package/src/search/__tests__/query-engine.test.ts +334 -0
- package/src/search/__tests__/similarity.test.ts +78 -0
- package/src/search/__tests__/vector-store.test.ts +281 -0
- package/src/search/chunk-extractor.ts +167 -0
- package/src/search/embedder.ts +209 -0
- package/src/search/graph-enricher.ts +95 -0
- package/src/search/indexer.ts +483 -0
- package/src/search/lexical-searcher.ts +190 -0
- package/src/search/query-engine.ts +225 -0
- package/src/search/vector-store.ts +311 -0
- package/src/types/index.ts +572 -0
- package/src/utils/__tests__/ansi.test.ts +54 -0
- package/src/utils/__tests__/frontmatter.test.ts +79 -0
- package/src/utils/__tests__/sanitize.test.ts +229 -0
- package/src/utils/ansi.ts +19 -0
- package/src/utils/context.ts +44 -0
- package/src/utils/frontmatter.ts +27 -0
- package/src/utils/sanitize.ts +78 -0
- package/test/e2e/lifecycle.test.ts +330 -0
- package/test/fixtures/mock-planner-hang.ts +5 -0
- package/test/fixtures/mock-planner.ts +26 -0
- package/test/fixtures/mock-reviewer-bad.ts +8 -0
- package/test/fixtures/mock-reviewer-retry.ts +34 -0
- package/test/fixtures/mock-reviewer.ts +18 -0
- package/test/fixtures/sample-project/src/circular-a.ts +6 -0
- package/test/fixtures/sample-project/src/circular-b.ts +6 -0
- package/test/fixtures/sample-project/src/config.ts +15 -0
- package/test/fixtures/sample-project/src/main.ts +19 -0
- package/test/fixtures/sample-project/src/services/product-service.ts +20 -0
- package/test/fixtures/sample-project/src/services/user-service.ts +18 -0
- package/test/fixtures/sample-project/src/types.ts +14 -0
- package/test/fixtures/sample-project/src/utils/index.ts +14 -0
- package/test/fixtures/sample-project/src/utils/validate.ts +12 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
# Certificate Enhancement Plan — Enterprise Grade
|
|
2
|
+
|
|
3
|
+
> **Document:** `enhance_plan.md`
|
|
4
|
+
> **Author:** Senior Technical Architect / CEO, nomos-arc.ai
|
|
5
|
+
> **Date:** 2026-04-04
|
|
6
|
+
> **Status:** Approved for Implementation
|
|
7
|
+
> **Scope:** Certificate v2 — Non-Repudiation, Governance Persistence, CI/CD Enforcement, Executive Reporting
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Executive Summary
|
|
12
|
+
|
|
13
|
+
The Certificate of AI Engineering Integrity (v1) establishes tamper-evidence through hash chaining and self-sealing. This is sufficient to prove *internal consistency* but insufficient for enterprise compliance. Three critical gaps remain:
|
|
14
|
+
|
|
15
|
+
1. **Non-Repudiation**: The certificate proves *what* happened but not *who* vouches for it. Without a digital signature bound to a developer identity, the certificate is an unsigned assertion.
|
|
16
|
+
2. **Governance Persistence**: The `rules_hash` proves rules *existed* at generation time but cannot reproduce them if the original files are deleted or modified. An auditor holding only the certificate has a hash with no content to verify against.
|
|
17
|
+
3. **Passive Artifact**: The certificate is generated but never enforced. Code can be merged without one. In regulated environments, an unenforced control is equivalent to no control.
|
|
18
|
+
|
|
19
|
+
Addressing these gaps transforms the certificate from a *documentation artifact* into a **cryptographic compliance gate** — the first in the AI-assisted engineering market. This positions nomos-arc.ai as the only tool that provides verifiable, enforceable, identity-bound proof of responsible AI engineering.
|
|
20
|
+
|
|
21
|
+
**Market impact**: Enterprise procurement in Banking, Healthcare, and Defense requires non-repudiation and CI/CD enforcement as baseline criteria. Without these, the certificate is a differentiator for demos but not for contracts.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. Digital Signature Layer (Non-Repudiation)
|
|
26
|
+
|
|
27
|
+
### 1.1 Problem Statement
|
|
28
|
+
|
|
29
|
+
The current `certificate_hash` proves the payload has not been modified since generation, but it does not bind the certificate to a human identity. Any process with write access to the certificate file can regenerate a valid `certificate_hash` after tampering with the content. The hash chain is tamper-evident but not tamper-proof without an external trust anchor.
|
|
30
|
+
|
|
31
|
+
### 1.2 Design
|
|
32
|
+
|
|
33
|
+
Integrate SSH and GPG signing to produce an identity-bound signature over the `certificate_hash`. The signature block is appended to the certificate payload *after* the self-seal, creating a layered integrity model:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Layer 1: chain_hash → proves history entry integrity
|
|
37
|
+
Layer 2: certificate_hash → proves payload integrity (self-seal)
|
|
38
|
+
Layer 3: signature → proves identity + non-repudiation
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 1.3 Implementation Steps
|
|
42
|
+
|
|
43
|
+
#### Step 1: Define the `SignatureBlock` schema
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
interface SignatureBlock {
|
|
47
|
+
signer: string; // e.g., "Ibrahim Magdy <ibrahim@nomos-arc.ai>"
|
|
48
|
+
method: 'ssh-ed25519' | 'ssh-rsa' | 'gpg';
|
|
49
|
+
key_fingerprint: string; // public key fingerprint for audit trail
|
|
50
|
+
signed_hash: string; // the certificate_hash that was signed
|
|
51
|
+
signature: string; // base64-encoded detached signature
|
|
52
|
+
signed_at: string; // ISO 8601
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The `SignatureBlock` is added as an optional field on `CertificatePayload`. It is *not* included in the `certificate_hash` computation — the signature signs the hash, not the payload. This preserves backward compatibility: unsigned certificates remain valid for v1 verification.
|
|
57
|
+
|
|
58
|
+
#### Step 2: Implement `arc certificate <task> --sign`
|
|
59
|
+
|
|
60
|
+
The `--sign` flag triggers the signing flow after certificate generation:
|
|
61
|
+
|
|
62
|
+
1. **Key discovery**: Check for available signing keys in order of preference:
|
|
63
|
+
- `ssh-agent` (via `SSH_AUTH_SOCK`): List keys with `ssh-add -L`, select the first ed25519 key.
|
|
64
|
+
- GPG keyring: Execute `gpg --list-secret-keys --keyid-format=long`, use the first available key.
|
|
65
|
+
- Explicit key path: `--sign-key <path>` flag for environments without agent.
|
|
66
|
+
|
|
67
|
+
2. **Signature computation**:
|
|
68
|
+
- Extract `certificate_hash` value (the hex string after `sha256:`).
|
|
69
|
+
- For SSH: Write hash to temp file, execute `ssh-keygen -Y sign -f <key> -n nomos-certificate <tempfile>`.
|
|
70
|
+
- For GPG: Pipe hash to `gpg --detach-sign --armor --local-user <keyid>`.
|
|
71
|
+
|
|
72
|
+
3. **Block assembly**: Populate `SignatureBlock` with signer identity (from `git config user.name` + `git config user.email`), method, fingerprint, signature output, and timestamp.
|
|
73
|
+
|
|
74
|
+
4. **Append to certificate**: Add `signature` field to the certificate JSON and write to disk. The `certificate_hash` is *not* recomputed — the signature is outside the seal.
|
|
75
|
+
|
|
76
|
+
#### Step 3: Implement signature verification in `--verify`
|
|
77
|
+
|
|
78
|
+
Add a 6th verification check: `signature_validity`.
|
|
79
|
+
|
|
80
|
+
- If `signature` block is absent: check is `SKIP` (not `FAIL`) — backward compatible.
|
|
81
|
+
- If present: verify that `signed_hash === certificate_hash`, then verify the cryptographic signature using the appropriate tool (`ssh-keygen -Y verify` or `gpg --verify`).
|
|
82
|
+
- Report signer identity and key fingerprint in the check detail.
|
|
83
|
+
|
|
84
|
+
#### Step 4: Key trust policy (optional, deferred)
|
|
85
|
+
|
|
86
|
+
For v2, nomos-arc.ai trusts any valid SSH/GPG signature — it proves *who* signed, not *whether they were authorized*. A future `allowed_signers` file (SSH) or trust-db (GPG) integration can restrict signing to approved identities.
|
|
87
|
+
|
|
88
|
+
### 1.4 Security Analysis
|
|
89
|
+
|
|
90
|
+
- **Threat mitigated**: An attacker who modifies the certificate and recomputes `certificate_hash` cannot forge a valid signature without the signer's private key.
|
|
91
|
+
- **Key compromise**: If a signing key is compromised, the attacker can produce valid signatures. Mitigation: key rotation policy and fingerprint logging in the certificate allow post-incident audit of which certificates were signed with the compromised key.
|
|
92
|
+
- **Non-repudiation**: The signer cannot deny having signed the certificate — the signature is verifiable against their public key.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 2. Governance Snapshot (Rules Persistence)
|
|
97
|
+
|
|
98
|
+
### 2.1 Problem Statement
|
|
99
|
+
|
|
100
|
+
The current certificate stores `rules.files` (file names) and `rules.rules_hash` (SHA-256 of concatenated content). This proves that specific rules *were loaded* during the task lifecycle, but if the rule files are later modified or deleted from the repository, an auditor cannot reconstruct what was enforced. The hash becomes unverifiable against thin air.
|
|
101
|
+
|
|
102
|
+
### 2.2 Design
|
|
103
|
+
|
|
104
|
+
Transition from "reference by hash" to "embedded context" by including a compressed summary of the active rules within the certificate. Two strategies, selected by content size:
|
|
105
|
+
|
|
106
|
+
| Strategy | Condition | Content |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| **Full embed** | Total rules content < 10 KB | Raw content of each rule file, keyed by filename |
|
|
109
|
+
| **Summary embed** | Total rules content >= 10 KB | First 200 lines per file + SHA-256 per file |
|
|
110
|
+
|
|
111
|
+
This ensures the certificate is self-contained for audit purposes without unbounded growth.
|
|
112
|
+
|
|
113
|
+
### 2.3 Implementation Steps
|
|
114
|
+
|
|
115
|
+
#### Step 1: Extend the `rules` section in `CertificatePayload`
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
rules: {
|
|
119
|
+
files: string[];
|
|
120
|
+
rules_hash: string;
|
|
121
|
+
// NEW — v2 addition
|
|
122
|
+
rules_snapshot: {
|
|
123
|
+
strategy: 'full' | 'summary';
|
|
124
|
+
content: Record<string, {
|
|
125
|
+
hash: string; // per-file SHA-256
|
|
126
|
+
body: string; // full content or truncated (first 200 lines)
|
|
127
|
+
truncated: boolean; // true if body is not the full file
|
|
128
|
+
}>;
|
|
129
|
+
total_size_bytes: number; // original total size before any truncation
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Step 2: Populate during `generate()`
|
|
135
|
+
|
|
136
|
+
In `CertificateEngine.generate()`, after loading the task state:
|
|
137
|
+
|
|
138
|
+
1. Read each file listed in `state.context.rules` from disk (resolve paths relative to `rules/` directory).
|
|
139
|
+
2. Compute per-file SHA-256.
|
|
140
|
+
3. If total content size < 10,240 bytes: embed full content, set `strategy: 'full'`.
|
|
141
|
+
4. If >= 10,240 bytes: truncate each file to first 200 lines, set `strategy: 'summary'`, mark `truncated: true`.
|
|
142
|
+
5. Verify that SHA-256 of concatenated *full* content matches `state.context.rules_hash` — if mismatch, warn that rules have been modified since task execution (do not block generation, but add a warning to output).
|
|
143
|
+
|
|
144
|
+
#### Step 3: Add verification check `rules_integrity`
|
|
145
|
+
|
|
146
|
+
A 7th verification check (or 6th if signature is absent):
|
|
147
|
+
|
|
148
|
+
- Recompute `rules_hash` from `rules_snapshot.content` (using full bodies only if `strategy: 'full'`).
|
|
149
|
+
- Compare with `rules.rules_hash`.
|
|
150
|
+
- If strategy is `summary` (truncated), the check can only verify per-file hashes, not the aggregate — mark as `PARTIAL`.
|
|
151
|
+
|
|
152
|
+
#### Step 4: Handle missing rule files gracefully
|
|
153
|
+
|
|
154
|
+
If a rule file listed in `state.context.rules` no longer exists on disk at certificate generation time:
|
|
155
|
+
|
|
156
|
+
- Log a warning: `Rule file "backend.md" no longer exists — embedding from state snapshot`.
|
|
157
|
+
- If the content is recoverable from git history (`git show HEAD:rules/backend.md`), use that.
|
|
158
|
+
- If not recoverable, embed `{ hash: state_hash, body: "[content unavailable — file deleted]", truncated: false }`.
|
|
159
|
+
- This is a **degraded** certificate — the `rules_integrity` check will note the gap.
|
|
160
|
+
|
|
161
|
+
### 2.4 Security Analysis
|
|
162
|
+
|
|
163
|
+
- **Threat mitigated**: Post-hoc rule modification to make a non-compliant task appear compliant. With embedded rules, the certificate is self-contained evidence of what was enforced.
|
|
164
|
+
- **Size concern**: The 10 KB threshold prevents certificate bloat. For projects with extensive rule sets, the summary strategy preserves auditability (per-file hashes) while bounding size.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 3. CI/CD Enforcement Gate (The "Hard Gate")
|
|
169
|
+
|
|
170
|
+
### 3.1 Problem Statement
|
|
171
|
+
|
|
172
|
+
The certificate is currently generated on-demand and never checked. A developer can merge code without ever running `arc certificate`. In regulated environments, an unenforced control is an audit finding, not a feature.
|
|
173
|
+
|
|
174
|
+
### 3.2 Design
|
|
175
|
+
|
|
176
|
+
A GitHub Action (`nomos-gate`) that runs as a required status check on pull requests. It performs four verifications and blocks merge if any fail:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
PR opened/updated
|
|
180
|
+
↓
|
|
181
|
+
nomos-gate action
|
|
182
|
+
├── 1. Certificate exists for this PR's head commit
|
|
183
|
+
├── 2. chain_hash is valid
|
|
184
|
+
├── 3. Digital signature is valid (if signing is required)
|
|
185
|
+
└── 4. base_commit matches PR head
|
|
186
|
+
↓
|
|
187
|
+
All pass → ✅ Status check passes
|
|
188
|
+
Any fail → ❌ Status check fails, merge blocked
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 3.3 Implementation Steps
|
|
192
|
+
|
|
193
|
+
#### Step 1: Define the GitHub Action (`action.yml`)
|
|
194
|
+
|
|
195
|
+
```yaml
|
|
196
|
+
name: 'nomos-arc Certificate Gate'
|
|
197
|
+
description: 'Verify AI Engineering Integrity Certificate before merge'
|
|
198
|
+
inputs:
|
|
199
|
+
certificate-path:
|
|
200
|
+
description: 'Path to the certificate JSON file'
|
|
201
|
+
required: false
|
|
202
|
+
default: 'tasks-management/certificates/*.certificate.json'
|
|
203
|
+
require-signature:
|
|
204
|
+
description: 'Require a valid digital signature'
|
|
205
|
+
required: false
|
|
206
|
+
default: 'false'
|
|
207
|
+
allowed-signers:
|
|
208
|
+
description: 'Path to allowed_signers file (SSH) for identity verification'
|
|
209
|
+
required: false
|
|
210
|
+
runs:
|
|
211
|
+
using: 'node20'
|
|
212
|
+
main: 'dist/gate/index.js'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### Step 2: Gate logic (`src/gate/index.ts`)
|
|
216
|
+
|
|
217
|
+
The gate action performs the following sequence:
|
|
218
|
+
|
|
219
|
+
1. **Certificate discovery**: Glob for `*.certificate.json` files matching the configured path. If no certificate found, fail with `MISSING_CERTIFICATE`.
|
|
220
|
+
|
|
221
|
+
2. **Parse + schema validation**: Use `CertificateEngine.parse()` to validate JSON structure. Fail with `INVALID_SCHEMA` on Zod errors.
|
|
222
|
+
|
|
223
|
+
3. **Full verification**: Run `CertificateEngine.verify()` — all 5 (or 7 with new checks) must pass.
|
|
224
|
+
|
|
225
|
+
4. **Commit binding**: Extract `repository.base_commit` from the certificate. Compare against the PR's head commit SHA (available via `github.event.pull_request.head.sha`). This proves the certificate was generated for *this specific code*, not a different version.
|
|
226
|
+
|
|
227
|
+
- **Matching strategy**: The certificate's `base_commit` is the commit the shadow branch forked from, while the PR's head SHA is the latest commit on the branch. The gate should verify that `base_commit` is an ancestor of the PR head commit, or that the PR's commit list includes changes from the shadow branch.
|
|
228
|
+
- Simplified v1: Verify that `repository.shadow_branch` matches the PR's head branch name. This is weaker but sufficient for MVP.
|
|
229
|
+
|
|
230
|
+
5. **Signature validation** (if `require-signature: true`):
|
|
231
|
+
- Check that `signature` block exists in the certificate.
|
|
232
|
+
- Verify the cryptographic signature using `ssh-keygen -Y verify` or `gpg --verify`.
|
|
233
|
+
- If `allowed-signers` is provided, verify the signer is in the allowed list.
|
|
234
|
+
|
|
235
|
+
6. **Result reporting**: Set the GitHub status check result. On failure, post a PR comment with the specific check failures for developer visibility.
|
|
236
|
+
|
|
237
|
+
#### Step 3: Output annotations
|
|
238
|
+
|
|
239
|
+
Use `@actions/core` to emit annotations:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
core.error('Certificate chain_hash verification failed', {
|
|
243
|
+
file: certificatePath,
|
|
244
|
+
title: 'nomos-arc Certificate Gate: CHAIN_HASH_INVALID',
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Step 4: Configuration in consumer repos
|
|
249
|
+
|
|
250
|
+
```yaml
|
|
251
|
+
# .github/workflows/nomos-gate.yml
|
|
252
|
+
name: nomos-arc Certificate Gate
|
|
253
|
+
on:
|
|
254
|
+
pull_request:
|
|
255
|
+
types: [opened, synchronize]
|
|
256
|
+
|
|
257
|
+
jobs:
|
|
258
|
+
verify:
|
|
259
|
+
runs-on: ubuntu-latest
|
|
260
|
+
steps:
|
|
261
|
+
- uses: actions/checkout@v4
|
|
262
|
+
- uses: nomos-arc/nomos-gate@v1
|
|
263
|
+
with:
|
|
264
|
+
require-signature: true
|
|
265
|
+
allowed-signers: .nomos/allowed_signers
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
#### Step 5: Branch protection integration
|
|
269
|
+
|
|
270
|
+
Document that the consumer must add `nomos-gate` as a required status check in GitHub branch protection settings. Without this, the action runs but doesn't block.
|
|
271
|
+
|
|
272
|
+
### 3.4 Security Analysis
|
|
273
|
+
|
|
274
|
+
- **Threat mitigated**: Merging code without a valid certificate, or using a certificate generated for a different branch/commit.
|
|
275
|
+
- **Bypass risk**: Repository admins can override required status checks. This is a GitHub platform limitation, not a nomos-arc.ai limitation. The certificate's immutable audit trail still records whether the gate was passed legitimately.
|
|
276
|
+
- **Commit binding weakness**: The MVP branch-name matching is weaker than full commit-ancestry verification. A developer could theoretically name a different branch identically. The full commit-ancestry check should be implemented in v2.1.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 4. Human-Centric Reporting (The Executive View)
|
|
281
|
+
|
|
282
|
+
### 4.1 Problem Statement
|
|
283
|
+
|
|
284
|
+
CTOs and auditors do not read JSON. The certificate in its current form is machine-readable but not board-ready. A compliance report must be visually professional, printable, and immediately interpretable by non-technical stakeholders.
|
|
285
|
+
|
|
286
|
+
### 4.2 Design
|
|
287
|
+
|
|
288
|
+
Implement `arc certificate <task> --format pdf` and `--format html` that render the certificate JSON into a professional compliance report.
|
|
289
|
+
|
|
290
|
+
### 4.3 Implementation Steps
|
|
291
|
+
|
|
292
|
+
#### Step 1: Template engine selection
|
|
293
|
+
|
|
294
|
+
Use a lightweight, zero-native-dependency approach:
|
|
295
|
+
|
|
296
|
+
| Option | Pros | Cons | Recommendation |
|
|
297
|
+
|---|---|---|---|
|
|
298
|
+
| `handlebars` + `puppeteer` | Full HTML/CSS control, PDF via Chrome headless | Puppeteer is ~400 MB | Only for environments with Chrome |
|
|
299
|
+
| `handlebars` + `@react-pdf/renderer` | React-based PDF, tree-shakeable | JSX dependency | Over-engineered for templates |
|
|
300
|
+
| **`ejs` + `html-pdf-node`** | Lightweight, template-based, Chromium-free | Less CSS control | **Recommended for CLI** |
|
|
301
|
+
| `handlebars` + raw HTML export | Zero new deps for HTML; PDF deferred | No PDF without browser | **Recommended for v2 MVP** |
|
|
302
|
+
|
|
303
|
+
**Decision**: For v2, implement HTML export using `handlebars` (single dependency, 72 KB). PDF generation via `--format pdf` deferred to v2.1 with `puppeteer` as an optional peer dependency — users who need PDF install it; the CLI stays lightweight.
|
|
304
|
+
|
|
305
|
+
#### Step 2: Report template structure
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
┌──────────────────────────────────────────────────┐
|
|
309
|
+
│ nomos-arc.ai — Certificate of AI Engineering │
|
|
310
|
+
│ Integrity │
|
|
311
|
+
│ │
|
|
312
|
+
│ ┌────────────────────────────────────────────┐ │
|
|
313
|
+
│ │ VERIFICATION STATUS: ✅ VALID │ │
|
|
314
|
+
│ │ Certificate Hash: sha256:2c624232c... │ │
|
|
315
|
+
│ │ Generated: 2026-04-04T12:00:00Z │ │
|
|
316
|
+
│ │ Signed by: Ibrahim Magdy (ssh-ed25519) │ │
|
|
317
|
+
│ └────────────────────────────────────────────┘ │
|
|
318
|
+
│ │
|
|
319
|
+
│ TASK SUMMARY │
|
|
320
|
+
│ ─────────────────────────────────────────────── │
|
|
321
|
+
│ Task ID: implement-auth-middleware │
|
|
322
|
+
│ Status: approved │
|
|
323
|
+
│ Iterations: 2 │
|
|
324
|
+
│ Final Score: 0.92 / 1.00 │
|
|
325
|
+
│ Approval: score_threshold │
|
|
326
|
+
│ │
|
|
327
|
+
│ REVIEW TRAIL │
|
|
328
|
+
│ ─────────────────────────────────────────────── │
|
|
329
|
+
│ Version 1: │
|
|
330
|
+
│ Planning: claude (supervised) │
|
|
331
|
+
│ Review: codex → 0.65 (1 high-severity issue) │
|
|
332
|
+
│ Version 2: │
|
|
333
|
+
│ Planning: claude (supervised) │
|
|
334
|
+
│ Review: codex → 0.92 (0 issues) │
|
|
335
|
+
│ │
|
|
336
|
+
│ GOVERNANCE │
|
|
337
|
+
│ ─────────────────────────────────────────────── │
|
|
338
|
+
│ Rules enforced: global.md, backend.md │
|
|
339
|
+
│ Rules hash: sha256:9f86d081884c... │
|
|
340
|
+
│ │
|
|
341
|
+
│ INTEGRITY │
|
|
342
|
+
│ ─────────────────────────────────────────────── │
|
|
343
|
+
│ Chain algorithm: sha256-sequential │
|
|
344
|
+
│ Chain hash: sha256:7d865e959b24... │
|
|
345
|
+
│ Entries: 4 │
|
|
346
|
+
│ │
|
|
347
|
+
│ BUDGET │
|
|
348
|
+
│ ─────────────────────────────────────────────── │
|
|
349
|
+
│ Total tokens: 8,600 │
|
|
350
|
+
│ Estimated cost: $0.02 │
|
|
351
|
+
│ │
|
|
352
|
+
│ ─────────────────────────────────────────────── │
|
|
353
|
+
│ Generated by nomos-arc@0.1.0 │
|
|
354
|
+
│ Verify: arc certificate <task> --verify │
|
|
355
|
+
└──────────────────────────────────────────────────┘
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### Step 3: Implement the rendering pipeline
|
|
359
|
+
|
|
360
|
+
1. Add `CertificateRenderer` class in `src/core/certificate-renderer.ts`.
|
|
361
|
+
2. Method `renderHTML(certificate: CertificatePayload, verificationResult?: VerificationResult): string`.
|
|
362
|
+
3. Load the Handlebars template from `src/templates/certificate-report.hbs`.
|
|
363
|
+
4. Inject certificate data, computed fields (formatted dates, score percentages, issue counts), and optional verification result.
|
|
364
|
+
5. Return the compiled HTML string.
|
|
365
|
+
|
|
366
|
+
#### Step 4: Wire into CLI
|
|
367
|
+
|
|
368
|
+
Extend the `--format` flag to accept `html`:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
if (opts.format === 'html') {
|
|
372
|
+
const renderer = new CertificateRenderer();
|
|
373
|
+
const result = engine.verify(certificate);
|
|
374
|
+
const html = renderer.renderHTML(certificate, result);
|
|
375
|
+
const htmlPath = certPath.replace('.json', '.html');
|
|
376
|
+
fs.writeFileSync(htmlPath, html, 'utf-8');
|
|
377
|
+
console.log(`Report saved to: ${htmlPath}`);
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
#### Step 5: CSS for print
|
|
382
|
+
|
|
383
|
+
Include a `@media print` stylesheet in the HTML template for direct browser-to-PDF printing. This provides a zero-dependency PDF path: open HTML in browser, print to PDF.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 5. Schema Updates
|
|
388
|
+
|
|
389
|
+
### 5.1 `CertificatePayload` interface changes (`src/types/index.ts`)
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
export interface CertificatePayload {
|
|
393
|
+
// Envelope
|
|
394
|
+
certificate_version: 1 | 2; // CHANGED: support v2
|
|
395
|
+
generated_at: string;
|
|
396
|
+
generator: string;
|
|
397
|
+
|
|
398
|
+
// Subject (unchanged)
|
|
399
|
+
task_id: string;
|
|
400
|
+
task_status: TaskStatus;
|
|
401
|
+
created_at: string;
|
|
402
|
+
completed_at: string;
|
|
403
|
+
|
|
404
|
+
// Repository provenance (unchanged)
|
|
405
|
+
repository: {
|
|
406
|
+
base_commit: string;
|
|
407
|
+
shadow_branch: string;
|
|
408
|
+
branch_status: 'active' | 'merged' | 'discarded';
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// AI provenance (unchanged)
|
|
412
|
+
models: {
|
|
413
|
+
planner: string;
|
|
414
|
+
reviewer: string;
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// Governance — EXTENDED
|
|
418
|
+
rules: {
|
|
419
|
+
files: string[];
|
|
420
|
+
rules_hash: string;
|
|
421
|
+
rules_snapshot?: { // NEW — v2
|
|
422
|
+
strategy: 'full' | 'summary';
|
|
423
|
+
content: Record<string, {
|
|
424
|
+
hash: string;
|
|
425
|
+
body: string;
|
|
426
|
+
truncated: boolean;
|
|
427
|
+
}>;
|
|
428
|
+
total_size_bytes: number;
|
|
429
|
+
};
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// Review trail (unchanged)
|
|
433
|
+
iterations: CertificateIteration[];
|
|
434
|
+
final_review: {
|
|
435
|
+
score: number;
|
|
436
|
+
summary: string;
|
|
437
|
+
issues: ReviewIssue[];
|
|
438
|
+
approval_reason: 'score_threshold' | 'max_iterations_reached';
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// Resources (unchanged)
|
|
442
|
+
budget: {
|
|
443
|
+
total_tokens: number;
|
|
444
|
+
estimated_cost_usd: number;
|
|
445
|
+
token_breakdown: { input_tokens: number; output_tokens: number };
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// Integrity (unchanged)
|
|
449
|
+
integrity: {
|
|
450
|
+
chain_hash: string;
|
|
451
|
+
entry_hashes: string[];
|
|
452
|
+
canonical_entries: string[];
|
|
453
|
+
chain_algorithm: 'sha256-sequential';
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// Self-seal (unchanged)
|
|
457
|
+
certificate_hash: string;
|
|
458
|
+
|
|
459
|
+
// Digital signature — NEW (v2, optional)
|
|
460
|
+
signature?: SignatureBlock;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// NEW interface
|
|
464
|
+
export interface SignatureBlock {
|
|
465
|
+
signer: string;
|
|
466
|
+
method: 'ssh-ed25519' | 'ssh-rsa' | 'gpg';
|
|
467
|
+
key_fingerprint: string;
|
|
468
|
+
signed_hash: string;
|
|
469
|
+
signature: string;
|
|
470
|
+
signed_at: string;
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### 5.2 Zod schema updates (`src/core/certificate.ts`)
|
|
475
|
+
|
|
476
|
+
- Add `SignatureBlockSchema` as an optional field on `CertificatePayloadSchema`.
|
|
477
|
+
- Add `RulesSnapshotSchema` within the `rules` object.
|
|
478
|
+
- Update `certificate_version` from `z.literal(1)` to `z.union([z.literal(1), z.literal(2)])`.
|
|
479
|
+
- All new fields are optional to maintain backward compatibility with v1 certificates.
|
|
480
|
+
|
|
481
|
+
### 5.3 Verification checks update
|
|
482
|
+
|
|
483
|
+
| # | Check | v1 | v2 |
|
|
484
|
+
|---|---|---|---|
|
|
485
|
+
| 1 | `status_validity` | Yes | Yes |
|
|
486
|
+
| 2 | `review_completeness` | Yes | Yes |
|
|
487
|
+
| 3 | `certificate_hash` | Yes | Yes |
|
|
488
|
+
| 4 | `chain_hash` | Yes | Yes |
|
|
489
|
+
| 5 | `entry_hash_consistency` | Yes | Yes |
|
|
490
|
+
| 6 | `signature_validity` | - | Yes (SKIP if unsigned) |
|
|
491
|
+
| 7 | `rules_integrity` | - | Yes (PARTIAL if summary) |
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## 6. Security Analysis
|
|
496
|
+
|
|
497
|
+
### 6.1 Threat Model
|
|
498
|
+
|
|
499
|
+
| Threat | Pre-Enhancement | Post-Enhancement |
|
|
500
|
+
|---|---|---|
|
|
501
|
+
| **Payload tampering** (modify score after generation) | Detected via `certificate_hash` | Detected via `certificate_hash` + signature prevents re-seal |
|
|
502
|
+
| **History rewriting** (alter iteration data) | Detected via `chain_hash` | Detected via `chain_hash` + signature prevents re-seal |
|
|
503
|
+
| **Identity spoofing** (claim someone else generated it) | Not addressed | Signature binds to SSH/GPG key identity |
|
|
504
|
+
| **Rule modification** (change rules after task completion) | Detected via `rules_hash` but unverifiable without originals | Full rules embedded — self-contained verification |
|
|
505
|
+
| **Certificate absence** (merge without certificate) | Not enforced | CI/CD gate blocks merge |
|
|
506
|
+
| **Certificate reuse** (use cert from different branch) | Not detected | `base_commit` binding in CI/CD gate |
|
|
507
|
+
| **Shadow AI** (using unapproved AI tools outside nomos-arc.ai) | Not addressed | Certificate absence in CI/CD blocks unauthorized AI work from merging without a process record |
|
|
508
|
+
|
|
509
|
+
### 6.2 Residual Risks
|
|
510
|
+
|
|
511
|
+
1. **Key compromise**: A compromised signing key allows forgery. Mitigation: key fingerprint logging enables post-incident audit.
|
|
512
|
+
2. **Admin override**: GitHub admins can bypass required status checks. Mitigation: the certificate audit trail persists independently.
|
|
513
|
+
3. **Offline tampering**: A developer with repo access can craft a fake certificate with valid structure. Mitigation: digital signature makes this computationally infeasible without the private key.
|
|
514
|
+
4. **Rule file unavailability**: If rule files are deleted before certificate generation, the snapshot will be incomplete. Mitigation: attempt git history recovery; flag as degraded.
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## 7. Success Metrics
|
|
519
|
+
|
|
520
|
+
### 7.1 Definition: Valid Enterprise Certificate
|
|
521
|
+
|
|
522
|
+
A certificate is "Enterprise Valid" when ALL of the following hold:
|
|
523
|
+
|
|
524
|
+
| Criterion | Verification Method |
|
|
525
|
+
|---|---|
|
|
526
|
+
| Task status is `approved` or `merged` | `status_validity` check |
|
|
527
|
+
| Final review exists with score and summary | `review_completeness` check |
|
|
528
|
+
| Payload has not been modified since generation | `certificate_hash` check |
|
|
529
|
+
| History entries have not been tampered with | `chain_hash` check |
|
|
530
|
+
| Entry hashes are consistent across data structures | `entry_hash_consistency` check |
|
|
531
|
+
| Certificate is signed by an identified developer | `signature_validity` check |
|
|
532
|
+
| Governance rules are embedded and hash-consistent | `rules_integrity` check |
|
|
533
|
+
| Certificate's base_commit is ancestor of merge target | CI/CD gate `commit_binding` check |
|
|
534
|
+
|
|
535
|
+
### 7.2 Implementation Success Criteria
|
|
536
|
+
|
|
537
|
+
| Metric | Target |
|
|
538
|
+
|---|---|
|
|
539
|
+
| All existing 26 tests continue to pass (backward compat) | 100% |
|
|
540
|
+
| New tests for signature, rules snapshot, and gate logic | >= 30 additional tests |
|
|
541
|
+
| v1 certificates verify correctly under v2 engine | Yes |
|
|
542
|
+
| v2 certificates with signature fail verification if tampered | Yes |
|
|
543
|
+
| CI/CD gate blocks merge when certificate is missing | Yes |
|
|
544
|
+
| CI/CD gate blocks merge when signature is invalid | Yes (when `require-signature: true`) |
|
|
545
|
+
| HTML report renders correctly for all certificate versions | Yes |
|
|
546
|
+
| No new runtime dependencies for core certificate engine | Yes (signature uses system SSH/GPG) |
|
|
547
|
+
| Single new dependency for HTML rendering (`handlebars`) | Yes |
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## 8. Implementation Priority and Sequencing
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
Phase 2a (Week 1-2): Governance Snapshot
|
|
555
|
+
└── Lowest risk, highest audit value, no external dependencies
|
|
556
|
+
├── Extend CertificatePayload schema
|
|
557
|
+
├── Implement rules reading + embedding in generate()
|
|
558
|
+
├── Add rules_integrity verification check
|
|
559
|
+
└── Tests: snapshot strategies, truncation, missing files
|
|
560
|
+
|
|
561
|
+
Phase 2b (Week 2-3): Digital Signature Layer
|
|
562
|
+
└── Requires system SSH/GPG — integration testing needed
|
|
563
|
+
├── Implement SignatureBlock and --sign flag
|
|
564
|
+
├── SSH signing via ssh-keygen
|
|
565
|
+
├── GPG signing via gpg CLI
|
|
566
|
+
├── Add signature_validity verification check
|
|
567
|
+
└── Tests: sign/verify round-trip, tampered signature, missing key
|
|
568
|
+
|
|
569
|
+
Phase 2c (Week 3-4): CI/CD Enforcement Gate
|
|
570
|
+
└── Depends on 2a + 2b for full gate logic
|
|
571
|
+
├── Create GitHub Action (nomos-gate)
|
|
572
|
+
├── Implement certificate discovery + verification
|
|
573
|
+
├── Implement commit binding check
|
|
574
|
+
├── Integration tests with mock GitHub context
|
|
575
|
+
└── Documentation: consumer repo setup
|
|
576
|
+
|
|
577
|
+
Phase 2d (Week 4): Executive Reporting
|
|
578
|
+
└── Independent of 2a-2c, can be parallelized
|
|
579
|
+
├── Add handlebars dependency
|
|
580
|
+
├── Create HTML template
|
|
581
|
+
├── Implement CertificateRenderer
|
|
582
|
+
├── Wire --format html into CLI
|
|
583
|
+
└── Tests: rendering with all certificate variants
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
## 9. Conclusion
|
|
589
|
+
|
|
590
|
+
These four enhancements transform the Certificate from a proof-of-concept into enterprise compliance infrastructure. The sequencing prioritizes audit value (governance snapshot) before cryptographic complexity (signatures) before enforcement (CI/CD gate), with reporting parallelized independently.
|
|
591
|
+
|
|
592
|
+
Upon completion, nomos-arc.ai will be the only AI engineering tool that provides:
|
|
593
|
+
- **Identity-bound** proof of responsible AI usage (signature)
|
|
594
|
+
- **Self-contained** governance evidence (rules snapshot)
|
|
595
|
+
- **Enforced** compliance gates (CI/CD action)
|
|
596
|
+
- **Board-ready** reporting (HTML/PDF export)
|
|
597
|
+
|
|
598
|
+
The certificate becomes the artifact that closes the deal in enterprise procurement.
|
|
599
|
+
|
|
600
|
+
```
|
|
601
|
+
arc certificate <task> --sign → The signed proof.
|
|
602
|
+
arc certificate <task> --verify → The full verification.
|
|
603
|
+
arc certificate <task> --format html → The executive report.
|
|
604
|
+
nomos-gate (GitHub Action) → The hard gate.
|
|
605
|
+
```
|