@codapult/guard 0.10.0 → 0.11.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/README.md +144 -4
- package/dist/adapters/agents/agent-integration.js +26 -3
- package/dist/cli/commands/guard.d.ts +2 -0
- package/dist/cli/commands/guard.js +77 -11
- package/dist/cli/index.js +2 -0
- package/dist/core/guard.d.ts +28 -1
- package/dist/core/guard.js +37 -0
- package/dist/core/history/runs.d.ts +64 -1
- package/dist/core/history/runs.js +109 -0
- package/dist/core/output/attestation.d.ts +17 -0
- package/dist/core/output/attestation.js +22 -0
- package/dist/core/policy/schemas.d.ts +47 -0
- package/dist/core/policy/schemas.js +67 -0
- package/dist/core/verification/github-actions.d.ts +25 -0
- package/dist/core/verification/github-actions.js +397 -0
- package/dist/core/verification/github-context.d.ts +8 -0
- package/dist/core/verification/github-context.js +41 -0
- package/dist/core/verification/verify.d.ts +23 -4
- package/dist/core/verification/verify.js +601 -47
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/prompts.js +7 -4
- package/dist/mcp/tools/guard.js +9 -3
- package/docs/extensions.md +79 -0
- package/docs/guard-agent-integration.md +51 -0
- package/docs/guard-ci.yml +202 -0
- package/docs/guard-fixtures.md +127 -0
- package/docs/guard-trusted-pr-attestation.yml +213 -0
- package/docs/guard.md +1125 -0
- package/docs/integrations/README.md +38 -0
- package/docs/integrations/claude-code.md +92 -0
- package/docs/integrations/codex.md +58 -0
- package/docs/integrations/cursor.md +116 -0
- package/docs/integrations/gemini-cli.md +47 -0
- package/docs/integrations/generic.md +41 -0
- package/docs/integrations/github-copilot.md +72 -0
- package/docs/policy-mutations.md +75 -0
- package/docs/releasing.md +58 -0
- package/docs/verify-guard-attestation.mjs +166 -0
- package/package.json +4 -2
|
@@ -46,6 +46,8 @@ function isGuardRunManifest(value) {
|
|
|
46
46
|
Number.isFinite(Date.parse(receipt.generatedAt)) &&
|
|
47
47
|
(receipt.outcome === 'pass' ||
|
|
48
48
|
receipt.outcome === 'fail' ||
|
|
49
|
+
receipt.outcome === 'incomplete' ||
|
|
50
|
+
receipt.outcome === 'policy-weakened' ||
|
|
49
51
|
receipt.outcome === 'warning' ||
|
|
50
52
|
receipt.outcome === 'needs-review' ||
|
|
51
53
|
receipt.outcome === 'not-configured') &&
|
|
@@ -65,7 +67,96 @@ function isGuardRunManifest(value) {
|
|
|
65
67
|
(receipt.subject.baseRef === undefined || typeof receipt.subject.baseRef === 'string') &&
|
|
66
68
|
(receipt.subject.baseCommit === undefined ||
|
|
67
69
|
typeof receipt.subject.baseCommit === 'string') &&
|
|
70
|
+
(receipt.subject.headSha === undefined || /^[a-f0-9]{40}$/i.test(receipt.subject.headSha)) &&
|
|
71
|
+
(receipt.subject.baseSha === undefined || /^[a-f0-9]{40}$/i.test(receipt.subject.baseSha)) &&
|
|
72
|
+
(receipt.subject.mergeSha === undefined ||
|
|
73
|
+
/^[a-f0-9]{40}$/i.test(receipt.subject.mergeSha)) &&
|
|
74
|
+
(receipt.subject.githubEvent === undefined ||
|
|
75
|
+
typeof receipt.subject.githubEvent === 'string') &&
|
|
68
76
|
(receipt.policy === undefined || isGuardRunPolicy(receipt.policy)) &&
|
|
77
|
+
(receipt.verificationScope === undefined ||
|
|
78
|
+
(receipt.verificationScope !== null &&
|
|
79
|
+
typeof receipt.verificationScope === 'object' &&
|
|
80
|
+
receipt.verificationScope.algorithm === 'sha256' &&
|
|
81
|
+
/^[a-f0-9]{64}$/.test(receipt.verificationScope.fingerprint) &&
|
|
82
|
+
typeof receipt.verificationScope.complete === 'boolean' &&
|
|
83
|
+
typeof receipt.verificationScope.stable === 'boolean' &&
|
|
84
|
+
Array.isArray(receipt.verificationScope.files) &&
|
|
85
|
+
receipt.verificationScope.files.every((file) => file !== null &&
|
|
86
|
+
typeof file === 'object' &&
|
|
87
|
+
typeof file.path === 'string' &&
|
|
88
|
+
(file.status === 'present' ||
|
|
89
|
+
file.status === 'deleted' ||
|
|
90
|
+
file.status === 'unavailable') &&
|
|
91
|
+
(file.status === 'unavailable'
|
|
92
|
+
? file.sha256 === undefined
|
|
93
|
+
: typeof file.sha256 === 'string' && /^[a-f0-9]{64}$/.test(file.sha256))))) &&
|
|
94
|
+
(receipt.policySurface === undefined ||
|
|
95
|
+
(receipt.policySurface !== null &&
|
|
96
|
+
typeof receipt.policySurface === 'object' &&
|
|
97
|
+
Array.isArray(receipt.policySurface.protectedPaths) &&
|
|
98
|
+
receipt.policySurface.protectedPaths.every((path) => typeof path === 'string') &&
|
|
99
|
+
Array.isArray(receipt.policySurface.changedPaths) &&
|
|
100
|
+
receipt.policySurface.changedPaths.every((path) => typeof path === 'string') &&
|
|
101
|
+
(receipt.policySurface.changes === undefined ||
|
|
102
|
+
(Array.isArray(receipt.policySurface.changes) &&
|
|
103
|
+
receipt.policySurface.changes.every((change) => change !== null &&
|
|
104
|
+
typeof change === 'object' &&
|
|
105
|
+
typeof change.path === 'string' &&
|
|
106
|
+
typeof change.pattern === 'string' &&
|
|
107
|
+
typeof change.kind === 'string' &&
|
|
108
|
+
(change.severity === 'warning' || change.severity === 'error')))) &&
|
|
109
|
+
Array.isArray(receipt.policySurface.suppressionMarkers) &&
|
|
110
|
+
receipt.policySurface.suppressionMarkers.every((marker) => typeof marker === 'string') &&
|
|
111
|
+
typeof receipt.policySurface.workflowChanged === 'boolean' &&
|
|
112
|
+
typeof receipt.policySurface.complete === 'boolean')) &&
|
|
113
|
+
(receipt.ciIntegrity === undefined ||
|
|
114
|
+
(receipt.ciIntegrity !== null &&
|
|
115
|
+
typeof receipt.ciIntegrity === 'object' &&
|
|
116
|
+
(receipt.ciIntegrity.status === 'ok' ||
|
|
117
|
+
receipt.ciIntegrity.status === 'policy-weakened' ||
|
|
118
|
+
receipt.ciIntegrity.status === 'incomplete') &&
|
|
119
|
+
Array.isArray(receipt.ciIntegrity.workflows) &&
|
|
120
|
+
receipt.ciIntegrity.workflows.every((workflow) => workflow !== null &&
|
|
121
|
+
typeof workflow === 'object' &&
|
|
122
|
+
typeof workflow.path === 'string' &&
|
|
123
|
+
typeof workflow.job === 'string' &&
|
|
124
|
+
(workflow.digest === undefined || typeof workflow.digest === 'string') &&
|
|
125
|
+
(workflow.baseDigest === undefined || typeof workflow.baseDigest === 'string') &&
|
|
126
|
+
Array.isArray(workflow.actions) &&
|
|
127
|
+
workflow.actions.every((action) => typeof action === 'string') &&
|
|
128
|
+
(workflow.baseActions === undefined ||
|
|
129
|
+
(Array.isArray(workflow.baseActions) &&
|
|
130
|
+
workflow.baseActions.every((action) => typeof action === 'string'))) &&
|
|
131
|
+
(workflow.actionChanges === undefined ||
|
|
132
|
+
(Array.isArray(workflow.actionChanges) &&
|
|
133
|
+
workflow.actionChanges.every((change) => change !== null &&
|
|
134
|
+
typeof change === 'object' &&
|
|
135
|
+
typeof change.name === 'string' &&
|
|
136
|
+
Array.isArray(change.base) &&
|
|
137
|
+
change.base.every((action) => typeof action === 'string') &&
|
|
138
|
+
Array.isArray(change.current) &&
|
|
139
|
+
change.current.every((action) => typeof action === 'string')))) &&
|
|
140
|
+
(workflow.status === 'ok' ||
|
|
141
|
+
workflow.status === 'policy-weakened' ||
|
|
142
|
+
workflow.status === 'incomplete') &&
|
|
143
|
+
Array.isArray(workflow.issues) &&
|
|
144
|
+
workflow.issues.every((issue) => issue !== null &&
|
|
145
|
+
typeof issue === 'object' &&
|
|
146
|
+
typeof issue.code === 'string' &&
|
|
147
|
+
typeof issue.message === 'string')))) &&
|
|
148
|
+
(receipt.requiredStages === undefined ||
|
|
149
|
+
(Array.isArray(receipt.requiredStages) &&
|
|
150
|
+
receipt.requiredStages.every((stage) => typeof stage === 'string'))) &&
|
|
151
|
+
(receipt.incompleteStages === undefined ||
|
|
152
|
+
(Array.isArray(receipt.incompleteStages) &&
|
|
153
|
+
receipt.incompleteStages.every((stage) => typeof stage === 'string'))) &&
|
|
154
|
+
(receipt.effectiveInvocation === undefined ||
|
|
155
|
+
(receipt.effectiveInvocation !== null &&
|
|
156
|
+
typeof receipt.effectiveInvocation === 'object' &&
|
|
157
|
+
typeof receipt.effectiveInvocation.command === 'string' &&
|
|
158
|
+
Array.isArray(receipt.effectiveInvocation.args) &&
|
|
159
|
+
receipt.effectiveInvocation.args.every((argument) => typeof argument === 'string'))) &&
|
|
69
160
|
receipt.stages !== null &&
|
|
70
161
|
typeof receipt.stages === 'object' &&
|
|
71
162
|
!Array.isArray(receipt.stages) &&
|
|
@@ -80,6 +171,14 @@ function isGuardRunManifest(value) {
|
|
|
80
171
|
return ((candidate.status === 'passed' ||
|
|
81
172
|
candidate.status === 'failed' ||
|
|
82
173
|
candidate.status === 'not-configured') &&
|
|
174
|
+
(candidate.command === undefined || typeof candidate.command === 'string') &&
|
|
175
|
+
(candidate.args === undefined ||
|
|
176
|
+
(Array.isArray(candidate.args) &&
|
|
177
|
+
candidate.args.every((argument) => typeof argument === 'string'))) &&
|
|
178
|
+
(candidate.execution === undefined ||
|
|
179
|
+
candidate.execution === 'attempted' ||
|
|
180
|
+
candidate.execution === 'rejected' ||
|
|
181
|
+
candidate.execution === 'not-configured') &&
|
|
83
182
|
Number.isInteger(candidate.exitCode) &&
|
|
84
183
|
typeof candidate.durationMs === 'number' &&
|
|
85
184
|
Number.isFinite(candidate.durationMs) &&
|
|
@@ -144,6 +243,8 @@ function isGuardRunManifest(value) {
|
|
|
144
243
|
manifest.durationMs >= 0 &&
|
|
145
244
|
(manifest.outcome === 'pass' ||
|
|
146
245
|
manifest.outcome === 'fail' ||
|
|
246
|
+
manifest.outcome === 'incomplete' ||
|
|
247
|
+
manifest.outcome === 'policy-weakened' ||
|
|
147
248
|
manifest.outcome === 'warning' ||
|
|
148
249
|
manifest.outcome === 'needs-review' ||
|
|
149
250
|
manifest.outcome === 'not-configured') &&
|
|
@@ -257,6 +358,8 @@ export function summarizeGuardRuns(root, limit = 100) {
|
|
|
257
358
|
total,
|
|
258
359
|
passed: runs.filter((run) => run.outcome === 'pass').length,
|
|
259
360
|
failed: runs.filter((run) => run.outcome === 'fail').length,
|
|
361
|
+
incomplete: runs.filter((run) => run.outcome === 'incomplete').length,
|
|
362
|
+
policyWeakened: runs.filter((run) => run.outcome === 'policy-weakened').length,
|
|
260
363
|
warnings: runs.filter((run) => run.outcome === 'warning').length,
|
|
261
364
|
averageDurationMs: total === 0 ? 0 : Math.round(runs.reduce((sum, run) => sum + run.durationMs, 0) / total),
|
|
262
365
|
...(total > 0 ? { last: runs[0] } : {}),
|
|
@@ -287,6 +390,12 @@ export function finishGuardRun(root, context, outcome, gate, command = 'verify',
|
|
|
287
390
|
workingTreeDirty: receipt?.subject.workingTreeDirty ?? false,
|
|
288
391
|
},
|
|
289
392
|
...(policy ? { policy } : {}),
|
|
393
|
+
...(receipt?.verificationScope ? { verificationScope: receipt.verificationScope } : {}),
|
|
394
|
+
...(receipt?.policySurface ? { policySurface: receipt.policySurface } : {}),
|
|
395
|
+
...(receipt?.ciIntegrity ? { ciIntegrity: receipt.ciIntegrity } : {}),
|
|
396
|
+
requiredStages: receipt?.requiredStages ?? [],
|
|
397
|
+
incompleteStages: receipt?.incompleteStages ?? [],
|
|
398
|
+
...(receipt?.effectiveInvocation ? { effectiveInvocation: receipt.effectiveInvocation } : {}),
|
|
290
399
|
stages: receipt?.stages ?? {},
|
|
291
400
|
checks: receipt?.checks ?? {},
|
|
292
401
|
findings: receipt?.findings ?? {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GuardVerificationReceipt } from '../history/runs.js';
|
|
2
|
+
export declare const GUARD_VERIFICATION_PREDICATE_TYPE = "https://codapult.dev/attestations/guard-verification/v1";
|
|
3
|
+
export interface GuardVerificationInTotoStatement {
|
|
4
|
+
_type: 'https://in-toto.io/Statement/v1';
|
|
5
|
+
subject: {
|
|
6
|
+
name: 'codapult-guard:verification-context';
|
|
7
|
+
digest: {
|
|
8
|
+
sha256: string;
|
|
9
|
+
};
|
|
10
|
+
}[];
|
|
11
|
+
predicateType: typeof GUARD_VERIFICATION_PREDICATE_TYPE;
|
|
12
|
+
predicate: {
|
|
13
|
+
receipt: GuardVerificationReceipt;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Bind a successful Guard receipt to the exact policy and file scope it verified. */
|
|
17
|
+
export declare function guardReceiptToInToto(receipt: GuardVerificationReceipt): GuardVerificationInTotoStatement;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const GUARD_VERIFICATION_PREDICATE_TYPE = 'https://codapult.dev/attestations/guard-verification/v1';
|
|
2
|
+
/** Bind a successful Guard receipt to the exact policy and file scope it verified. */
|
|
3
|
+
export function guardReceiptToInToto(receipt) {
|
|
4
|
+
const scope = receipt.verificationScope;
|
|
5
|
+
if (receipt.outcome !== 'pass' ||
|
|
6
|
+
!scope?.complete ||
|
|
7
|
+
!scope.stable ||
|
|
8
|
+
!/^[a-f0-9]{64}$/.test(scope.fingerprint)) {
|
|
9
|
+
throw new Error('Only a passing receipt with a complete, stable verification scope can be attested.');
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
_type: 'https://in-toto.io/Statement/v1',
|
|
13
|
+
subject: [
|
|
14
|
+
{
|
|
15
|
+
name: 'codapult-guard:verification-context',
|
|
16
|
+
digest: { sha256: scope.fingerprint },
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
predicateType: GUARD_VERIFICATION_PREDICATE_TYPE,
|
|
20
|
+
predicate: { receipt },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -226,6 +226,44 @@ export declare const guardConfigSchema: z.ZodObject<{
|
|
|
226
226
|
warningDays: z.ZodNumber;
|
|
227
227
|
maxDays: z.ZodOptional<z.ZodNumber>;
|
|
228
228
|
}, z.core.$strip>>;
|
|
229
|
+
protectedPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
230
|
+
policySurface: z.ZodOptional<z.ZodObject<{
|
|
231
|
+
paths: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
232
|
+
pattern: z.ZodString;
|
|
233
|
+
kind: z.ZodEnum<{
|
|
234
|
+
"ci-workflow": "ci-workflow";
|
|
235
|
+
custom: "custom";
|
|
236
|
+
"dependency-input": "dependency-input";
|
|
237
|
+
"guard-policy": "guard-policy";
|
|
238
|
+
"ignore-config": "ignore-config";
|
|
239
|
+
ownership: "ownership";
|
|
240
|
+
"suppression-source": "suppression-source";
|
|
241
|
+
"tool-config": "tool-config";
|
|
242
|
+
}>;
|
|
243
|
+
severity: z.ZodDefault<z.ZodEnum<{
|
|
244
|
+
error: "error";
|
|
245
|
+
warning: "warning";
|
|
246
|
+
}>>;
|
|
247
|
+
}, z.core.$strip>>>;
|
|
248
|
+
}, z.core.$strip>>;
|
|
249
|
+
githubActions: z.ZodOptional<z.ZodObject<{
|
|
250
|
+
workflows: z.ZodArray<z.ZodObject<{
|
|
251
|
+
path: z.ZodString;
|
|
252
|
+
job: z.ZodString;
|
|
253
|
+
requiredRunIncludes: z.ZodArray<z.ZodString>;
|
|
254
|
+
requiredNeeds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
255
|
+
requirePullRequest: z.ZodDefault<z.ZodBoolean>;
|
|
256
|
+
requireUnfilteredPullRequest: z.ZodDefault<z.ZodBoolean>;
|
|
257
|
+
requireUnconditionalJob: z.ZodDefault<z.ZodBoolean>;
|
|
258
|
+
requireFullShaActions: z.ZodDefault<z.ZodBoolean>;
|
|
259
|
+
disallowContinueOnError: z.ZodDefault<z.ZodBoolean>;
|
|
260
|
+
maxPermissions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
261
|
+
none: "none";
|
|
262
|
+
read: "read";
|
|
263
|
+
write: "write";
|
|
264
|
+
}>>>;
|
|
265
|
+
}, z.core.$strip>>;
|
|
266
|
+
}, z.core.$strip>>;
|
|
229
267
|
}, z.core.$strip>;
|
|
230
268
|
export declare const guardContractsFileSchema: z.ZodObject<{
|
|
231
269
|
version: z.ZodLiteral<1>;
|
|
@@ -408,5 +446,14 @@ export declare const guardAgentConfigSchema: z.ZodObject<{
|
|
|
408
446
|
test: "test";
|
|
409
447
|
typecheck: "typecheck";
|
|
410
448
|
}>>;
|
|
449
|
+
requiredStages: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
450
|
+
adapters: "adapters";
|
|
451
|
+
"architecture-policy": "architecture-policy";
|
|
452
|
+
"ci-integrity": "ci-integrity";
|
|
453
|
+
"policy-surface": "policy-surface";
|
|
454
|
+
"project-checks": "project-checks";
|
|
455
|
+
runtime: "runtime";
|
|
456
|
+
"verification-scope": "verification-scope";
|
|
457
|
+
}>>>;
|
|
411
458
|
}, z.core.$strip>;
|
|
412
459
|
}, z.core.$strip>;
|
|
@@ -89,6 +89,61 @@ export const guardConfigSchema = z.object({
|
|
|
89
89
|
path: ['maxDays'],
|
|
90
90
|
})
|
|
91
91
|
.optional(),
|
|
92
|
+
protectedPaths: z
|
|
93
|
+
.array(z
|
|
94
|
+
.string()
|
|
95
|
+
.trim()
|
|
96
|
+
.min(1)
|
|
97
|
+
.refine((path) => !path.startsWith('/') && !path.includes('\\') && !path.split('/').includes('..'), 'protectedPaths entries must be repository-relative paths without parent traversal'))
|
|
98
|
+
.optional(),
|
|
99
|
+
policySurface: z
|
|
100
|
+
.object({
|
|
101
|
+
paths: z
|
|
102
|
+
.array(z.object({
|
|
103
|
+
pattern: z
|
|
104
|
+
.string()
|
|
105
|
+
.trim()
|
|
106
|
+
.min(1)
|
|
107
|
+
.refine((path) => !path.startsWith('/') && !path.includes('\\') && !path.split('/').includes('..'), 'policySurface paths must be repository-relative without parent traversal'),
|
|
108
|
+
kind: z.enum([
|
|
109
|
+
'ci-workflow',
|
|
110
|
+
'guard-policy',
|
|
111
|
+
'ownership',
|
|
112
|
+
'dependency-input',
|
|
113
|
+
'tool-config',
|
|
114
|
+
'ignore-config',
|
|
115
|
+
'suppression-source',
|
|
116
|
+
'custom',
|
|
117
|
+
]),
|
|
118
|
+
severity: z.enum(['warning', 'error']).default('error'),
|
|
119
|
+
}))
|
|
120
|
+
.default([]),
|
|
121
|
+
})
|
|
122
|
+
.optional(),
|
|
123
|
+
githubActions: z
|
|
124
|
+
.object({
|
|
125
|
+
workflows: z
|
|
126
|
+
.array(z.object({
|
|
127
|
+
path: z
|
|
128
|
+
.string()
|
|
129
|
+
.trim()
|
|
130
|
+
.min(1)
|
|
131
|
+
.refine((path) => !path.startsWith('/') && !path.includes('\\') && !path.split('/').includes('..'), 'GitHub Actions workflow paths must be repository-relative without parent traversal'),
|
|
132
|
+
job: z.string().trim().min(1),
|
|
133
|
+
requiredRunIncludes: z.array(z.string().trim().min(1)).min(1),
|
|
134
|
+
requiredNeeds: z.array(z.string().trim().min(1)).optional(),
|
|
135
|
+
requirePullRequest: z.boolean().default(true),
|
|
136
|
+
requireUnfilteredPullRequest: z.boolean().default(true),
|
|
137
|
+
requireUnconditionalJob: z.boolean().default(true),
|
|
138
|
+
requireFullShaActions: z.boolean().default(true),
|
|
139
|
+
disallowContinueOnError: z.boolean().default(true),
|
|
140
|
+
maxPermissions: z
|
|
141
|
+
.record(z.string().trim().min(1), z.enum(['none', 'read', 'write']))
|
|
142
|
+
.optional(),
|
|
143
|
+
}))
|
|
144
|
+
.min(1),
|
|
145
|
+
})
|
|
146
|
+
.optional(),
|
|
92
147
|
});
|
|
93
148
|
export const guardContractsFileSchema = z.object({
|
|
94
149
|
version: z.literal(1),
|
|
@@ -167,5 +222,17 @@ export const guardAgentConfigSchema = z.object({
|
|
|
167
222
|
maxIterations: z.number().int().min(1).max(10),
|
|
168
223
|
projectChecks: z.boolean(),
|
|
169
224
|
checks: z.array(z.enum(['lint', 'typecheck', 'test', 'build'])),
|
|
225
|
+
requiredStages: z
|
|
226
|
+
.array(z.enum([
|
|
227
|
+
'runtime',
|
|
228
|
+
'project-checks',
|
|
229
|
+
'adapters',
|
|
230
|
+
'architecture-policy',
|
|
231
|
+
'policy-surface',
|
|
232
|
+
'ci-integrity',
|
|
233
|
+
'verification-scope',
|
|
234
|
+
]))
|
|
235
|
+
.min(1)
|
|
236
|
+
.default(['architecture-policy']),
|
|
170
237
|
}),
|
|
171
238
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { GuardGitHubActionsPolicy } from '../guard.js';
|
|
2
|
+
export interface GuardCiIntegrityIssue {
|
|
3
|
+
code: 'workflow-unreadable' | 'workflow-invalid' | 'pull-request-trigger-missing' | 'pull-request-filtered' | 'pull-request-target-present' | 'job-missing' | 'job-conditional' | 'command-missing' | 'step-conditional' | 'continue-on-error' | 'dependency-missing' | 'dependency-conditional' | 'dependency-continue-on-error' | 'action-not-sha-pinned' | 'action-reference-changed' | 'base-workflow-unavailable' | 'permission-expansion';
|
|
4
|
+
message: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GuardCiIntegrityWorkflowResult {
|
|
7
|
+
path: string;
|
|
8
|
+
job: string;
|
|
9
|
+
digest?: string | undefined;
|
|
10
|
+
baseDigest?: string | undefined;
|
|
11
|
+
actions: string[];
|
|
12
|
+
baseActions?: string[] | undefined;
|
|
13
|
+
actionChanges?: {
|
|
14
|
+
name: string;
|
|
15
|
+
base: string[];
|
|
16
|
+
current: string[];
|
|
17
|
+
}[] | undefined;
|
|
18
|
+
status: 'ok' | 'policy-weakened' | 'incomplete';
|
|
19
|
+
issues: GuardCiIntegrityIssue[];
|
|
20
|
+
}
|
|
21
|
+
export interface GuardCiIntegrityResult {
|
|
22
|
+
status: 'ok' | 'policy-weakened' | 'incomplete';
|
|
23
|
+
workflows: GuardCiIntegrityWorkflowResult[];
|
|
24
|
+
}
|
|
25
|
+
export declare function auditGitHubActions(root: string, policy: GuardGitHubActionsPolicy | undefined, baseRef?: string): GuardCiIntegrityResult | undefined;
|