@oh-my-pi/pi-coding-agent 17.2.0 → 17.2.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.
- package/CHANGELOG.md +18 -0
- package/dist/{CHANGELOG-be1f2t8h.md → CHANGELOG-dj46zzrm.md} +18 -0
- package/dist/cli.js +3340 -3195
- package/dist/types/config/model-discovery.d.ts +12 -0
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +23 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/security-protocol.d.ts +15 -0
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/sdk.d.ts +17 -0
- package/dist/types/security/auth.d.ts +30 -0
- package/dist/types/security/cloud.d.ts +79 -0
- package/dist/types/security/comparison.d.ts +49 -0
- package/dist/types/security/contracts/ids.d.ts +15 -0
- package/dist/types/security/contracts/index.d.ts +4 -0
- package/dist/types/security/contracts/schemas.d.ts +660 -0
- package/dist/types/security/contracts/types.d.ts +234 -0
- package/dist/types/security/contracts/validation.d.ts +5 -0
- package/dist/types/security/coordinator.d.ts +100 -0
- package/dist/types/security/importers/codex-security.d.ts +7 -0
- package/dist/types/security/importers/index.d.ts +2 -0
- package/dist/types/security/importers/sarif.d.ts +9 -0
- package/dist/types/security/index.d.ts +13 -0
- package/dist/types/security/preflight.d.ts +61 -0
- package/dist/types/security/provenance.d.ts +24 -0
- package/dist/types/security/publication.d.ts +78 -0
- package/dist/types/security/remediation.d.ts +27 -0
- package/dist/types/security/resource-output.d.ts +8 -0
- package/dist/types/security/sarif.d.ts +2 -0
- package/dist/types/security/store.d.ts +40 -0
- package/dist/types/slash-commands/helpers/security.d.ts +2 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/tools/builtin-names.d.ts +1 -1
- package/dist/types/tools/index.d.ts +6 -1
- package/dist/types/tools/security-scan.d.ts +96 -0
- package/package.json +12 -12
- package/scripts/security-compare.ts +40 -0
- package/src/config/model-discovery.ts +32 -5
- package/src/config/model-registry.ts +4 -0
- package/src/config/settings-schema.ts +12 -0
- package/src/eval/py/prelude.py +7 -3
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +53 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/router.ts +4 -1
- package/src/internal-urls/security-protocol.ts +261 -0
- package/src/internal-urls/types.ts +1 -1
- package/src/lsp/index.ts +3 -0
- package/src/modes/rpc/host-uris.ts +6 -0
- package/src/prompts/agents/security-reviewer.md +75 -0
- package/src/prompts/security/scan-coordinator.md +7 -0
- package/src/prompts/security/scan-request.md +21 -0
- package/src/prompts/security/validate-request.md +8 -0
- package/src/prompts/system/system-prompt.md +3 -0
- package/src/prompts/tools/security-publish.md +1 -0
- package/src/prompts/tools/security-scan.md +1 -0
- package/src/sdk.ts +34 -6
- package/src/security/auth.ts +98 -0
- package/src/security/cloud.ts +686 -0
- package/src/security/comparison.ts +255 -0
- package/src/security/contracts/ids.ts +111 -0
- package/src/security/contracts/index.ts +4 -0
- package/src/security/contracts/schemas.ts +201 -0
- package/src/security/contracts/types.ts +254 -0
- package/src/security/contracts/validation.ts +65 -0
- package/src/security/coordinator.ts +708 -0
- package/src/security/importers/codex-security.ts +387 -0
- package/src/security/importers/index.ts +2 -0
- package/src/security/importers/sarif.ts +357 -0
- package/src/security/index.ts +13 -0
- package/src/security/preflight.ts +405 -0
- package/src/security/provenance.ts +106 -0
- package/src/security/publication.ts +326 -0
- package/src/security/remediation.ts +93 -0
- package/src/security/resource-output.ts +50 -0
- package/src/security/sarif.ts +78 -0
- package/src/security/store.ts +430 -0
- package/src/slash-commands/builtin-registry.ts +21 -0
- package/src/slash-commands/helpers/security.ts +451 -0
- package/src/system-prompt.ts +4 -0
- package/src/task/agents.ts +2 -0
- package/src/task/executor.ts +3 -0
- package/src/task/structured-subagent.ts +6 -4
- package/src/tools/builtin-names.ts +1 -0
- package/src/tools/index.ts +9 -1
- package/src/tools/path-utils.ts +3 -0
- package/src/tools/security-scan.ts +287 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
export type SecuritySeverityLevel = "critical" | "high" | "medium" | "low" | "informational";
|
|
2
|
+
export type SecurityConfidenceLevel = "high" | "medium" | "low";
|
|
3
|
+
export type SecurityScanStatus = "planned" | "running" | "completed" | "partial" | "cancelled" | "failed";
|
|
4
|
+
export type SecurityCoverageCompleteness = "complete" | "partial" | "unknown";
|
|
5
|
+
export type SecurityValidationStatus = "unvalidated" | "validated" | "rejected" | "partial" | "error";
|
|
6
|
+
export type SecurityDispositionStatus = "open" | "false_positive" | "accepted_risk" | "fixed" | "wont_fix";
|
|
7
|
+
export type SecurityTargetKind = "repository" | "scoped_path" | "ref_diff" | "working_tree" | "imported";
|
|
8
|
+
export type SecurityProducerKind = "omp-native" | "codex-security-bundle" | "codex-security-cloud" | "sarif-import";
|
|
9
|
+
|
|
10
|
+
export interface SecurityProducer {
|
|
11
|
+
kind: SecurityProducerKind;
|
|
12
|
+
name: string;
|
|
13
|
+
version?: string;
|
|
14
|
+
vendor?: string;
|
|
15
|
+
revision?: string;
|
|
16
|
+
pluginVersion?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SecurityUpstreamProvenance {
|
|
20
|
+
repository?: string;
|
|
21
|
+
revision?: string;
|
|
22
|
+
packageVersion?: string;
|
|
23
|
+
pluginVersion?: string;
|
|
24
|
+
archiveSha256?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface SecurityProvenance {
|
|
28
|
+
producer: SecurityProducer;
|
|
29
|
+
createdAt: string;
|
|
30
|
+
importedAt?: string;
|
|
31
|
+
sourceIds?: Record<string, string>;
|
|
32
|
+
vendorFingerprints?: Record<string, string>;
|
|
33
|
+
upstream?: SecurityUpstreamProvenance;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SecurityLocation {
|
|
38
|
+
path: string;
|
|
39
|
+
startLine: number;
|
|
40
|
+
endLine?: number;
|
|
41
|
+
startColumn?: number;
|
|
42
|
+
endColumn?: number;
|
|
43
|
+
role?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface SecurityEvidence {
|
|
47
|
+
id: string;
|
|
48
|
+
kind: "code" | "trace" | "validation" | "note";
|
|
49
|
+
label: string;
|
|
50
|
+
explanation: string;
|
|
51
|
+
location?: SecurityLocation;
|
|
52
|
+
excerpt?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SecurityOccurrence {
|
|
56
|
+
id: string;
|
|
57
|
+
locations: SecurityLocation[];
|
|
58
|
+
evidenceIds: string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface SecuritySeverity {
|
|
62
|
+
level: SecuritySeverityLevel;
|
|
63
|
+
score?: number;
|
|
64
|
+
scoringSystem?: string;
|
|
65
|
+
vector?: string;
|
|
66
|
+
rationale?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface SecurityConfidence {
|
|
70
|
+
level: SecurityConfidenceLevel;
|
|
71
|
+
rationale?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface SecurityTaxonomy {
|
|
75
|
+
category: string;
|
|
76
|
+
cwe: string[];
|
|
77
|
+
tags?: string[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface SecurityValidation {
|
|
81
|
+
status: SecurityValidationStatus;
|
|
82
|
+
summary?: string;
|
|
83
|
+
evidenceIds: string[];
|
|
84
|
+
validatedAt?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface SecurityDisposition {
|
|
88
|
+
status: SecurityDispositionStatus;
|
|
89
|
+
rationale?: string;
|
|
90
|
+
updatedAt?: string;
|
|
91
|
+
actor?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface SecurityFinding {
|
|
95
|
+
id: string;
|
|
96
|
+
scanId: string;
|
|
97
|
+
fingerprint: string;
|
|
98
|
+
ruleId: string;
|
|
99
|
+
anchor?: string;
|
|
100
|
+
title: string;
|
|
101
|
+
summary: string;
|
|
102
|
+
severity: SecuritySeverity;
|
|
103
|
+
confidence: SecurityConfidence;
|
|
104
|
+
taxonomy: SecurityTaxonomy;
|
|
105
|
+
occurrences: SecurityOccurrence[];
|
|
106
|
+
evidence: SecurityEvidence[];
|
|
107
|
+
remediation?: string;
|
|
108
|
+
validation: SecurityValidation;
|
|
109
|
+
disposition: SecurityDisposition;
|
|
110
|
+
provenance: SecurityProvenance;
|
|
111
|
+
extensions?: Record<string, unknown>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface SecurityCoverageSurface {
|
|
115
|
+
id: string;
|
|
116
|
+
label: string;
|
|
117
|
+
disposition: "reported" | "no_issue_found" | "rejected" | "not_applicable" | "needs_follow_up";
|
|
118
|
+
receiptRefs: string[];
|
|
119
|
+
riskArea?: string;
|
|
120
|
+
notes?: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface SecurityCoverageDeferred {
|
|
124
|
+
id: string;
|
|
125
|
+
reason: string;
|
|
126
|
+
paths?: string[];
|
|
127
|
+
surfaceIds?: string[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface SecurityCoverage {
|
|
131
|
+
mode: "repository" | "scoped_path" | "diff" | "working_tree" | "deep_repository" | "imported";
|
|
132
|
+
completeness: SecurityCoverageCompleteness;
|
|
133
|
+
inventoryStrategy: "repository" | "scoped_path" | "diff" | "directory" | "custom" | "imported";
|
|
134
|
+
includePaths: string[];
|
|
135
|
+
excludePaths: string[];
|
|
136
|
+
surfaces: SecurityCoverageSurface[];
|
|
137
|
+
explicitExclusions: Array<{ pattern: string; reason: string }>;
|
|
138
|
+
deferred: SecurityCoverageDeferred[];
|
|
139
|
+
openQuestions?: Array<{ question: string; followUpPrompt?: string }>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface SecurityTarget {
|
|
143
|
+
kind: SecurityTargetKind;
|
|
144
|
+
repositoryRoot: string;
|
|
145
|
+
displayName: string;
|
|
146
|
+
revision?: string;
|
|
147
|
+
baseRevision?: string;
|
|
148
|
+
headRevision?: string;
|
|
149
|
+
includePaths: string[];
|
|
150
|
+
excludePaths: string[];
|
|
151
|
+
treeDigest: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface SecurityModelRef {
|
|
155
|
+
provider: string;
|
|
156
|
+
modelId: string;
|
|
157
|
+
thinkingLevel?: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface SecurityAccountRef {
|
|
161
|
+
provider: string;
|
|
162
|
+
credentialId: number;
|
|
163
|
+
accountId?: string;
|
|
164
|
+
email?: string;
|
|
165
|
+
organizationId?: string;
|
|
166
|
+
organizationName?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface SecurityKnowledgeBaseRef {
|
|
170
|
+
path: string;
|
|
171
|
+
sha256: string;
|
|
172
|
+
size: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface SecurityOutputPlan {
|
|
176
|
+
root: string;
|
|
177
|
+
archiveExisting: boolean;
|
|
178
|
+
existingState: "absent" | "empty" | "archivable";
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface SecurityScanPlan {
|
|
182
|
+
documentType: "omp-security.scan-plan";
|
|
183
|
+
schemaVersion: "1.0";
|
|
184
|
+
id: string;
|
|
185
|
+
createdAt: string;
|
|
186
|
+
repositoryRoot: string;
|
|
187
|
+
target: SecurityTarget;
|
|
188
|
+
knowledgeBases: SecurityKnowledgeBaseRef[];
|
|
189
|
+
output: SecurityOutputPlan;
|
|
190
|
+
model: SecurityModelRef;
|
|
191
|
+
account: SecurityAccountRef;
|
|
192
|
+
configFingerprint: string;
|
|
193
|
+
workflowFingerprint: string;
|
|
194
|
+
fingerprint: string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface SecurityScanMetrics {
|
|
198
|
+
runtimeMs?: number;
|
|
199
|
+
tokenUsage?: {
|
|
200
|
+
input: number;
|
|
201
|
+
output: number;
|
|
202
|
+
reasoning: number;
|
|
203
|
+
cacheRead: number;
|
|
204
|
+
cacheWrite: number;
|
|
205
|
+
total: number;
|
|
206
|
+
};
|
|
207
|
+
cost?: number;
|
|
208
|
+
premiumRequests?: number;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface SecurityScan {
|
|
212
|
+
documentType: "omp-security.scan";
|
|
213
|
+
schemaVersion: "1.0";
|
|
214
|
+
id: string;
|
|
215
|
+
projectKey: string;
|
|
216
|
+
status: SecurityScanStatus;
|
|
217
|
+
createdAt: string;
|
|
218
|
+
startedAt?: string;
|
|
219
|
+
completedAt?: string;
|
|
220
|
+
plan?: SecurityScanPlan;
|
|
221
|
+
target: SecurityTarget;
|
|
222
|
+
producer: SecurityProducer;
|
|
223
|
+
provenance: SecurityProvenance;
|
|
224
|
+
findingIds: string[];
|
|
225
|
+
coverage: SecurityCoverage;
|
|
226
|
+
reportRef?: string;
|
|
227
|
+
sarifRef?: string;
|
|
228
|
+
error?: string;
|
|
229
|
+
metrics?: SecurityScanMetrics;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface SecurityScanBundle {
|
|
233
|
+
scan: SecurityScan;
|
|
234
|
+
findings: SecurityFinding[];
|
|
235
|
+
report?: string;
|
|
236
|
+
sarif?: Record<string, unknown>;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface SecurityFindingMatch {
|
|
240
|
+
beforeFindingId?: string;
|
|
241
|
+
afterFindingId?: string;
|
|
242
|
+
fingerprint: string;
|
|
243
|
+
status: "unchanged" | "new" | "resolved";
|
|
244
|
+
matchBasis?: "fingerprint" | "rule_location" | "taxonomy_location";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface SecurityComparisonReport {
|
|
248
|
+
beforeScanId: string;
|
|
249
|
+
afterScanId: string;
|
|
250
|
+
matches: SecurityFindingMatch[];
|
|
251
|
+
unchanged: number;
|
|
252
|
+
introduced: number;
|
|
253
|
+
resolved: number;
|
|
254
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import { securityFindingSchema, securityScanBundleSchema, securityScanPlanSchema, securityScanSchema } from "./schemas";
|
|
3
|
+
import type { SecurityFinding, SecurityScan, SecurityScanBundle, SecurityScanPlan } from "./types";
|
|
4
|
+
|
|
5
|
+
function schemaError(label: string, errors: type.errors): Error {
|
|
6
|
+
return new Error(`${label} failed schema validation: ${errors.summary}`);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function parseSecurityFinding(value: unknown): SecurityFinding {
|
|
10
|
+
const result = securityFindingSchema(value);
|
|
11
|
+
if (result instanceof type.errors) throw schemaError("Security finding", result);
|
|
12
|
+
return result as SecurityFinding;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function parseSecurityScan(value: unknown): SecurityScan {
|
|
16
|
+
const result = securityScanSchema(value);
|
|
17
|
+
if (result instanceof type.errors) throw schemaError("Security scan", result);
|
|
18
|
+
return result as SecurityScan;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function parseSecurityScanPlan(value: unknown): SecurityScanPlan {
|
|
22
|
+
const result = securityScanPlanSchema(value);
|
|
23
|
+
if (result instanceof type.errors) throw schemaError("Security scan plan", result);
|
|
24
|
+
return result as SecurityScanPlan;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function parseSecurityScanBundle(value: unknown): SecurityScanBundle {
|
|
28
|
+
const result = securityScanBundleSchema(value);
|
|
29
|
+
if (result instanceof type.errors) throw schemaError("Security scan bundle", result);
|
|
30
|
+
const bundle = result as SecurityScanBundle;
|
|
31
|
+
const findingIds = new Set(bundle.findings.map(finding => finding.id));
|
|
32
|
+
if (findingIds.size !== bundle.findings.length) throw new Error("Security scan contains duplicate finding ids");
|
|
33
|
+
const referencedFindingIds = new Set(bundle.scan.findingIds);
|
|
34
|
+
if (referencedFindingIds.size !== bundle.scan.findingIds.length) {
|
|
35
|
+
throw new Error("Security scan manifest contains duplicate finding references");
|
|
36
|
+
}
|
|
37
|
+
for (const findingId of referencedFindingIds) {
|
|
38
|
+
if (!findingIds.has(findingId)) throw new Error(`Security scan references missing finding: ${findingId}`);
|
|
39
|
+
}
|
|
40
|
+
for (const findingId of findingIds) {
|
|
41
|
+
if (!referencedFindingIds.has(findingId))
|
|
42
|
+
throw new Error(`Security scan omits finding from manifest: ${findingId}`);
|
|
43
|
+
}
|
|
44
|
+
for (const finding of bundle.findings) {
|
|
45
|
+
if (finding.scanId !== bundle.scan.id) {
|
|
46
|
+
throw new Error(`Finding ${finding.id} belongs to ${finding.scanId}, expected ${bundle.scan.id}`);
|
|
47
|
+
}
|
|
48
|
+
const evidenceIds = new Set(finding.evidence.map(evidence => evidence.id));
|
|
49
|
+
if (evidenceIds.size !== finding.evidence.length) {
|
|
50
|
+
throw new Error(`Finding ${finding.id} contains duplicate evidence ids`);
|
|
51
|
+
}
|
|
52
|
+
const occurrenceIds = new Set(finding.occurrences.map(occurrence => occurrence.id));
|
|
53
|
+
if (occurrenceIds.size !== finding.occurrences.length) {
|
|
54
|
+
throw new Error(`Finding ${finding.id} contains duplicate occurrence ids`);
|
|
55
|
+
}
|
|
56
|
+
for (const occurrence of finding.occurrences) {
|
|
57
|
+
for (const evidenceId of occurrence.evidenceIds) {
|
|
58
|
+
if (!evidenceIds.has(evidenceId)) {
|
|
59
|
+
throw new Error(`Occurrence ${occurrence.id} references missing evidence: ${evidenceId}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return bundle;
|
|
65
|
+
}
|