@devtrack-solution/codesdd 1.2.4-rc3 → 1.2.4
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/.sdd/skills/curated/devtrack-api/SKILL.md +91 -12
- package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +3 -3
- package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +59 -3
- package/.sdd/skills/curated/devtrack-api/references/consumer-sync-policy.md +15 -3
- package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +1898 -2
- package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +3 -1
- package/.sdd/skills/curated/devtrack-api/references/field-validation-protocol.md +40 -0
- package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +20 -2
- package/.sdd/skills/curated/devtrack-api/references/generated-artifact-invalidation.md +97 -0
- package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +30 -1
- package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +4 -3
- package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +22 -1
- package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +9 -5
- package/README.md +122 -25
- package/dist/cli/program.js +180 -11
- package/dist/commands/config.js +27 -1
- package/dist/commands/sdd/execution.js +64 -2
- package/dist/commands/sdd.js +119 -4
- package/dist/core/cli/command-matrix.d.ts +18 -0
- package/dist/core/cli/command-matrix.js +148 -0
- package/dist/core/cli-command-quality.js +2 -0
- package/dist/core/config-schema.d.ts +14 -1
- package/dist/core/config-schema.js +32 -1
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +11 -0
- package/dist/core/global-config.d.ts +13 -0
- package/dist/core/init.d.ts +2 -2
- package/dist/core/init.js +13 -14
- package/dist/core/sdd/agent-binding.d.ts +9 -9
- package/dist/core/sdd/agent-runtime-contract.d.ts +4 -4
- package/dist/core/sdd/allocator-recovery.d.ts +14 -0
- package/dist/core/sdd/allocator-recovery.js +30 -0
- package/dist/core/sdd/allocator-security.d.ts +18 -0
- package/dist/core/sdd/allocator-security.js +36 -0
- package/dist/core/sdd/api-foundation-baseline.d.ts +111 -0
- package/dist/core/sdd/api-foundation-baseline.js +151 -0
- package/dist/core/sdd/api-foundation-parity.d.ts +114 -0
- package/dist/core/sdd/api-foundation-parity.js +131 -0
- package/dist/core/sdd/api-profile-catalog.d.ts +36 -0
- package/dist/core/sdd/api-profile-catalog.js +132 -0
- package/dist/core/sdd/api-profile-dry-run-projection.d.ts +93 -0
- package/dist/core/sdd/api-profile-dry-run-projection.js +370 -0
- package/dist/core/sdd/api-profile-recipes.d.ts +82 -0
- package/dist/core/sdd/api-profile-recipes.js +484 -0
- package/dist/core/sdd/artifact-id-allocator.d.ts +368 -0
- package/dist/core/sdd/artifact-id-allocator.js +510 -0
- package/dist/core/sdd/check.d.ts +50 -1
- package/dist/core/sdd/check.js +286 -9
- package/dist/core/sdd/deepagent-contracts.d.ts +4 -4
- package/dist/core/sdd/deepagents/reversa-subagents.d.ts +3 -3
- package/dist/core/sdd/default-bootstrap-files.d.ts +1 -1
- package/dist/core/sdd/default-bootstrap-files.js +0 -2
- package/dist/core/sdd/default-skills.js +7 -5
- package/dist/core/sdd/devtrack-api-appliance.d.ts +34 -0
- package/dist/core/sdd/devtrack-api-appliance.js +138 -34
- package/dist/core/sdd/devtrack-api-architecture.d.ts +16 -0
- package/dist/core/sdd/devtrack-api-architecture.js +86 -0
- package/dist/core/sdd/docs-sync.js +3 -3
- package/dist/core/sdd/enterprise-mutating-command-gate.d.ts +27 -0
- package/dist/core/sdd/enterprise-mutating-command-gate.js +104 -0
- package/dist/core/sdd/enterprise-provenance-gates.d.ts +20 -0
- package/dist/core/sdd/enterprise-provenance-gates.js +63 -0
- package/dist/core/sdd/enterprise-provisioning-policy.d.ts +26 -0
- package/dist/core/sdd/enterprise-provisioning-policy.js +104 -0
- package/dist/core/sdd/governance-schemas.d.ts +2 -2
- package/dist/core/sdd/governance-schemas.js +11 -2
- package/dist/core/sdd/json-schema.js +4 -0
- package/dist/core/sdd/legacy-operations.js +93 -4
- package/dist/core/sdd/package-security-gates.js +2 -0
- package/dist/core/sdd/package-structure-gate.d.ts +85 -3
- package/dist/core/sdd/package-structure-gate.js +386 -8
- package/dist/core/sdd/parallel-feat-automation.d.ts +6 -6
- package/dist/core/sdd/plugin-policy.js +6 -1
- package/dist/core/sdd/plugin-registry.d.ts +3 -3
- package/dist/core/sdd/quality-validation.d.ts +5 -5
- package/dist/core/sdd/release-readiness.d.ts +49 -0
- package/dist/core/sdd/release-readiness.js +303 -8
- package/dist/core/sdd/reversa-architecture-extractor.d.ts +13 -0
- package/dist/core/sdd/reversa-architecture-extractor.js +89 -0
- package/dist/core/sdd/reversa-artifact-writer.d.ts +18 -0
- package/dist/core/sdd/reversa-artifact-writer.js +40 -0
- package/dist/core/sdd/reversa-command-policy.d.ts +136 -0
- package/dist/core/sdd/reversa-command-policy.js +361 -0
- package/dist/core/sdd/reversa-data-extractor.d.ts +11 -0
- package/dist/core/sdd/reversa-data-extractor.js +73 -0
- package/dist/core/sdd/reversa-equivalence.d.ts +20 -0
- package/dist/core/sdd/reversa-equivalence.js +34 -0
- package/dist/core/sdd/reversa-evidence.d.ts +298 -0
- package/dist/core/sdd/reversa-evidence.js +118 -0
- package/dist/core/sdd/reversa-reconstruction.d.ts +29 -0
- package/dist/core/sdd/reversa-reconstruction.js +32 -0
- package/dist/core/sdd/reversa-rules-extractor.d.ts +12 -0
- package/dist/core/sdd/reversa-rules-extractor.js +86 -0
- package/dist/core/sdd/reversa-source-safety.d.ts +19 -0
- package/dist/core/sdd/reversa-source-safety.js +105 -0
- package/dist/core/sdd/reversa-surface-scout.d.ts +13 -0
- package/dist/core/sdd/reversa-surface-scout.js +85 -0
- package/dist/core/sdd/reversa-ux-mapper.d.ts +11 -0
- package/dist/core/sdd/reversa-ux-mapper.js +73 -0
- package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +1 -1
- package/dist/core/sdd/services/archive-quality-coherence.service.d.ts +17 -0
- package/dist/core/sdd/services/archive-quality-coherence.service.js +141 -0
- package/dist/core/sdd/services/decide.service.js +1 -1
- package/dist/core/sdd/services/finalize.service.d.ts +2 -0
- package/dist/core/sdd/services/finalize.service.js +48 -2
- package/dist/core/sdd/services/historical-quality-regression.service.d.ts +35 -0
- package/dist/core/sdd/services/historical-quality-regression.service.js +228 -0
- package/dist/core/sdd/services/ingest-deposito.service.js +1 -1
- package/dist/core/sdd/services/planning-execution-coherence.service.d.ts +45 -0
- package/dist/core/sdd/services/planning-execution-coherence.service.js +225 -0
- package/dist/core/sdd/state.js +15 -5
- package/dist/core/sdd/types.d.ts +3 -3
- package/dist/core/sdd/workspace-schemas.d.ts +45 -4
- package/dist/core/sdd/workspace-schemas.js +27 -6
- package/dist/core/shared/skill-generation.d.ts +2 -0
- package/dist/core/shared/skill-generation.js +19 -2
- package/dist/core/shared/tool-detection.d.ts +19 -0
- package/dist/core/shared/tool-detection.js +89 -0
- package/package.json +6 -5
- package/schemas/sdd/5-quality.schema.json +43 -0
- package/schemas/sdd/reversa-evidence-bundle.schema.json +466 -0
- package/schemas/sdd/workspace-catalog.schema.json +511 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { buildPluginRuntimeInvocationPlan, pluginArtifactManifestSchema, } from './plugin-broker.js';
|
|
2
2
|
import { pluginManifestSchema } from './plugin-manifest.js';
|
|
3
3
|
import { createPluginRegistryState } from './plugin-registry.js';
|
|
4
|
+
import { DEFAULT_CODESDD_API_PROFILE_ID, resolveCodeSddApiProfile, } from './api-profile-catalog.js';
|
|
5
|
+
import { CODESDD_API_FOUNDATION_SHARED_BASELINE, CODESDD_API_SHARED_BASELINE_QUALITY_GATES, CODESDD_API_SHARED_BASELINE_REQUIREMENTS, getCodeSddApiSharedBaselineRequirements, } from './api-foundation-baseline.js';
|
|
6
|
+
import { CODESDD_FULL_FOUNDATION_COMPATIBLE_PROFILE_ID, CODESDD_FULL_FOUNDATION_PARITY_DIMENSIONS, CODESDD_FULL_FOUNDATION_PARITY_MATRIX, CODESDD_FULL_FOUNDATION_PARITY_QUALITY_GATES, getCodeSddFullFoundationParityMatrix, } from './api-foundation-parity.js';
|
|
7
|
+
import { buildCodeSddApiProfileDryRunProjection, getCodeSddApiProfileDryRunExpectation, } from './api-profile-dry-run-projection.js';
|
|
4
8
|
export const DEVTRACK_API_APPLIANCE_PLUGIN_ID = 'codesdd-plugin-devtrack-api';
|
|
5
9
|
export const DEVTRACK_API_APPLIANCE_CAPABILITIES = [
|
|
6
10
|
'scaffold.project',
|
|
@@ -17,10 +21,12 @@ const DEVTRACK_API_SCAFFOLD_WRITE_SCOPE = [
|
|
|
17
21
|
'src',
|
|
18
22
|
'tests',
|
|
19
23
|
'docs',
|
|
24
|
+
'.env.example',
|
|
20
25
|
'package.json',
|
|
21
26
|
'tsconfig.json',
|
|
22
27
|
'nest-cli.json',
|
|
23
28
|
'eslint.config.mjs',
|
|
29
|
+
'.sdd/plugin-evidence',
|
|
24
30
|
];
|
|
25
31
|
export function evaluateDevTrackApiApplianceConformance(manifest) {
|
|
26
32
|
const parsed = pluginManifestSchema.parse(manifest);
|
|
@@ -52,6 +58,9 @@ export function buildDevTrackApiScaffoldDryRunPlan(manifest, input) {
|
|
|
52
58
|
const parsed = pluginManifestSchema.parse(manifest);
|
|
53
59
|
const createdAt = input.created_at ?? new Date().toISOString();
|
|
54
60
|
const packageName = normalizePackageName(input.package_name ?? input.project_name);
|
|
61
|
+
const apiProfile = resolveCodeSddApiProfile(input.api_profile, {
|
|
62
|
+
defaultProfile: DEFAULT_CODESDD_API_PROFILE_ID,
|
|
63
|
+
});
|
|
55
64
|
const conformance = evaluateDevTrackApiApplianceConformance(parsed);
|
|
56
65
|
if (!conformance.valid) {
|
|
57
66
|
return {
|
|
@@ -64,8 +73,8 @@ export function buildDevTrackApiScaffoldDryRunPlan(manifest, input) {
|
|
|
64
73
|
issues: conformance.issues,
|
|
65
74
|
};
|
|
66
75
|
}
|
|
67
|
-
const artifacts = buildScaffoldArtifacts();
|
|
68
|
-
const runtimePlan = buildRuntimePlan(parsed, input, packageName, createdAt, artifacts);
|
|
76
|
+
const artifacts = buildScaffoldArtifacts(apiProfile.profile_id);
|
|
77
|
+
const runtimePlan = buildRuntimePlan(parsed, input, packageName, createdAt, artifacts, apiProfile);
|
|
69
78
|
if (runtimePlan.status !== 'ready' || !runtimePlan.envelope) {
|
|
70
79
|
return {
|
|
71
80
|
schema_version: 1,
|
|
@@ -89,6 +98,7 @@ export function buildDevTrackApiScaffoldDryRunPlan(manifest, input) {
|
|
|
89
98
|
status: 'planned',
|
|
90
99
|
created_at: createdAt,
|
|
91
100
|
operation_id: operationId,
|
|
101
|
+
api_profile: apiProfile,
|
|
92
102
|
project_name: input.project_name,
|
|
93
103
|
package_name: packageName,
|
|
94
104
|
runtime_plan: runtimePlan,
|
|
@@ -129,6 +139,9 @@ export function buildDevTrackApiScaffoldDryRunPlan(manifest, input) {
|
|
|
129
139
|
projectName: input.project_name,
|
|
130
140
|
packageName,
|
|
131
141
|
validationCommands: parsed.validation.commands,
|
|
142
|
+
apiProfile,
|
|
143
|
+
expectedWriteScope: runtimePlan.envelope.write_scope,
|
|
144
|
+
artifacts,
|
|
132
145
|
}),
|
|
133
146
|
issues: [],
|
|
134
147
|
};
|
|
@@ -146,7 +159,7 @@ function collectIdentityIssues(manifest) {
|
|
|
146
159
|
}
|
|
147
160
|
return issues;
|
|
148
161
|
}
|
|
149
|
-
function buildRuntimePlan(manifest, input, packageName, createdAt, artifacts) {
|
|
162
|
+
function buildRuntimePlan(manifest, input, packageName, createdAt, artifacts, apiProfile) {
|
|
150
163
|
const registry = createPluginRegistryState([
|
|
151
164
|
{
|
|
152
165
|
manifest,
|
|
@@ -161,10 +174,12 @@ function buildRuntimePlan(manifest, input, packageName, createdAt, artifacts) {
|
|
|
161
174
|
return buildPluginRuntimeInvocationPlan(registry, {
|
|
162
175
|
feature_ref: input.feature_ref,
|
|
163
176
|
capability: DEVTRACK_API_SCAFFOLD_CAPABILITY,
|
|
164
|
-
skill_ref:
|
|
177
|
+
skill_ref: apiProfile.profile_id,
|
|
165
178
|
inputs: {
|
|
166
179
|
project_name: input.project_name,
|
|
167
180
|
package_name: packageName,
|
|
181
|
+
api_profile: apiProfile.profile_id,
|
|
182
|
+
api_profile_family: apiProfile.family_id,
|
|
168
183
|
persistence: {
|
|
169
184
|
provider: 'typeorm',
|
|
170
185
|
},
|
|
@@ -187,6 +202,35 @@ function buildRuntimePlan(manifest, input, packageName, createdAt, artifacts) {
|
|
|
187
202
|
});
|
|
188
203
|
}
|
|
189
204
|
function buildEvidenceManifest(input) {
|
|
205
|
+
const sharedBaselineRequirements = getCodeSddApiSharedBaselineRequirements();
|
|
206
|
+
const fullFoundationCompatibility = input.apiProfile.profile_id === CODESDD_FULL_FOUNDATION_COMPATIBLE_PROFILE_ID
|
|
207
|
+
? {
|
|
208
|
+
id: CODESDD_FULL_FOUNDATION_PARITY_MATRIX.id,
|
|
209
|
+
version: CODESDD_FULL_FOUNDATION_PARITY_MATRIX.version,
|
|
210
|
+
profile_id: CODESDD_FULL_FOUNDATION_COMPATIBLE_PROFILE_ID,
|
|
211
|
+
source: CODESDD_FULL_FOUNDATION_PARITY_MATRIX.foundation_reference,
|
|
212
|
+
dimension_ids: CODESDD_FULL_FOUNDATION_PARITY_DIMENSIONS,
|
|
213
|
+
quality_gates: CODESDD_FULL_FOUNDATION_PARITY_QUALITY_GATES,
|
|
214
|
+
dimensions: getCodeSddFullFoundationParityMatrix().map((dimension) => ({
|
|
215
|
+
...dimension,
|
|
216
|
+
status: 'pending',
|
|
217
|
+
})),
|
|
218
|
+
}
|
|
219
|
+
: undefined;
|
|
220
|
+
const profileProjection = buildCodeSddApiProfileDryRunProjection({
|
|
221
|
+
apiProfile: input.apiProfile,
|
|
222
|
+
expectedWriteScope: input.expectedWriteScope,
|
|
223
|
+
artifactMapRefs: input.artifacts.map((artifactEntry) => ({
|
|
224
|
+
path: artifactEntry.path,
|
|
225
|
+
layer: artifactEntry.layer,
|
|
226
|
+
artifact_kind: artifactEntry.artifact_kind,
|
|
227
|
+
role: artifactEntry.role,
|
|
228
|
+
content_type: artifactEntry.content_type,
|
|
229
|
+
source_reference: artifactEntry.source_reference,
|
|
230
|
+
tags: artifactEntry.tags,
|
|
231
|
+
})),
|
|
232
|
+
validationCommands: input.validationCommands,
|
|
233
|
+
});
|
|
190
234
|
return {
|
|
191
235
|
schema_version: 1,
|
|
192
236
|
operation_id: input.operationId,
|
|
@@ -207,43 +251,100 @@ function buildEvidenceManifest(input) {
|
|
|
207
251
|
command,
|
|
208
252
|
status: 'pending',
|
|
209
253
|
})),
|
|
210
|
-
quality_gates: [
|
|
211
|
-
|
|
254
|
+
quality_gates: unique([
|
|
255
|
+
...profileProjection.expected_quality_gates,
|
|
212
256
|
'no-secret-fixtures',
|
|
213
257
|
'no-out-of-root-writes',
|
|
214
258
|
'artifact-manifest-required',
|
|
215
259
|
'evidence-manifest-required',
|
|
216
|
-
],
|
|
260
|
+
]),
|
|
261
|
+
api_profile: {
|
|
262
|
+
family_id: input.apiProfile.family_id,
|
|
263
|
+
selected_profile: input.apiProfile.profile_id,
|
|
264
|
+
requested_profile: input.apiProfile.input,
|
|
265
|
+
legacy_alias: input.apiProfile.legacy_alias,
|
|
266
|
+
migration_notice: input.apiProfile.migration_notice,
|
|
267
|
+
inherited_baseline: CODESDD_API_SHARED_BASELINE_REQUIREMENTS,
|
|
268
|
+
},
|
|
269
|
+
profile_projection: profileProjection,
|
|
270
|
+
foundation_baseline: {
|
|
271
|
+
id: CODESDD_API_FOUNDATION_SHARED_BASELINE.id,
|
|
272
|
+
version: CODESDD_API_FOUNDATION_SHARED_BASELINE.version,
|
|
273
|
+
source: CODESDD_API_FOUNDATION_SHARED_BASELINE.foundation_reference,
|
|
274
|
+
requirement_ids: CODESDD_API_SHARED_BASELINE_REQUIREMENTS,
|
|
275
|
+
quality_gates: CODESDD_API_SHARED_BASELINE_QUALITY_GATES,
|
|
276
|
+
requirements: sharedBaselineRequirements,
|
|
277
|
+
},
|
|
278
|
+
...(fullFoundationCompatibility
|
|
279
|
+
? {
|
|
280
|
+
full_foundation_compatibility: fullFoundationCompatibility,
|
|
281
|
+
}
|
|
282
|
+
: {}),
|
|
217
283
|
};
|
|
218
284
|
}
|
|
219
|
-
function buildScaffoldArtifacts() {
|
|
220
|
-
|
|
221
|
-
artifact('package.json', 'root', 'package-metadata', 'manifest', 'application/json', 'Foundation-compatible package metadata, scripts, and dependencies.'),
|
|
222
|
-
artifact('
|
|
223
|
-
artifact('
|
|
224
|
-
artifact('
|
|
225
|
-
artifact('
|
|
226
|
-
artifact('
|
|
227
|
-
artifact('src/
|
|
228
|
-
artifact('src/
|
|
229
|
-
artifact('src/application/
|
|
230
|
-
artifact('src/
|
|
231
|
-
artifact('src/
|
|
232
|
-
artifact('src/
|
|
233
|
-
artifact('src/
|
|
234
|
-
artifact('src/
|
|
235
|
-
artifact('src/
|
|
236
|
-
artifact('src/
|
|
237
|
-
artifact('src/
|
|
238
|
-
artifact('src/
|
|
239
|
-
artifact('src/presentation/
|
|
240
|
-
artifact('src/
|
|
241
|
-
artifact('src/
|
|
242
|
-
artifact('
|
|
243
|
-
artifact('
|
|
285
|
+
function buildScaffoldArtifacts(apiProfile) {
|
|
286
|
+
const baselineArtifacts = [
|
|
287
|
+
artifact('package.json', 'root', 'package-metadata', 'manifest', 'application/json', 'Foundation-compatible package metadata, scripts, and dependencies.', apiProfile),
|
|
288
|
+
artifact('.env.example', 'config', 'configuration', 'manifest', 'text/plain', 'Safe placeholder environment contract, including app, database, JWT, and Swagger server variables.', apiProfile),
|
|
289
|
+
artifact('tsconfig.json', 'config', 'configuration', 'manifest', 'application/json', 'TypeScript path aliases and compiler settings aligned to Foundation API.', apiProfile),
|
|
290
|
+
artifact('nest-cli.json', 'config', 'configuration', 'manifest', 'application/json', 'Nest CLI configuration with Swagger plugin support.', apiProfile),
|
|
291
|
+
artifact('eslint.config.mjs', 'config', 'configuration', 'policy', 'text/javascript', 'Foundation-compatible lint rules and import-boundary checks.', apiProfile),
|
|
292
|
+
artifact('docs/foundation-backend-reference-structure.md', 'docs', 'documentation', 'documentation', 'text/markdown', 'Derived Foundation package structure reference for maintainers.', apiProfile),
|
|
293
|
+
artifact('src/main.ts', 'root', 'source', 'implementation', 'text/typescript', 'NestJS bootstrap entrypoint with validation pipe and Swagger/OpenAPI /docs setup.', apiProfile),
|
|
294
|
+
artifact('src/app.module.ts', 'root', 'source', 'module', 'text/typescript', 'Root module composing application, infrastructure, and presentation layers.', apiProfile),
|
|
295
|
+
artifact('src/application/application.module.ts', 'application', 'source', 'module', 'text/typescript', 'Application layer module boundary.', apiProfile),
|
|
296
|
+
artifact('src/application/runtime-settings.ts', 'application', 'source', 'type', 'text/typescript', 'Application runtime settings boundary.', apiProfile),
|
|
297
|
+
artifact('src/domain/auth/business-objects/api-keys.bo.ts', 'domain', 'source', 'business-object', 'text/typescript', 'Initial BO-pattern domain object example from Foundation API.', apiProfile),
|
|
298
|
+
artifact('src/application/business/auth/ports/out/api-key-repository.port.ts', 'application', 'source', 'repository-port', 'text/typescript', 'BO-pattern repository port owned by application ports/out.', apiProfile),
|
|
299
|
+
artifact('src/application/business/auth/ports/in/register.use-case.port.ts', 'application', 'source', 'interface', 'text/typescript', 'Application input port for a user-facing auth route.', apiProfile),
|
|
300
|
+
artifact('src/application/business/auth/use-cases/register.use-case.ts', 'application', 'source', 'use-case', 'text/typescript', 'Application use case backing a user-facing route before presentation wiring.', apiProfile),
|
|
301
|
+
artifact('src/application/business/auth/auth.application.module.ts', 'application', 'source', 'module', 'text/typescript', 'Application auth module wiring input ports, use cases, services, and output ports.', apiProfile),
|
|
302
|
+
artifact('src/infrastructure/infrastructure.module.ts', 'infrastructure', 'source', 'module', 'text/typescript', 'Infrastructure layer module boundary.', apiProfile),
|
|
303
|
+
artifact('src/infrastructure/settings/app-configuration.ts', 'infrastructure', 'source', 'implementation', 'text/typescript', 'Typed application configuration source.', apiProfile),
|
|
304
|
+
artifact('src/infrastructure/adapters/orm/entities/api-key.orm-entity.ts', 'infrastructure', 'source', 'entity', 'text/typescript', 'TypeORM persistence entity kept in the centralized orm subsystem.', apiProfile),
|
|
305
|
+
artifact('src/presentation/presentation.module.ts', 'presentation', 'source', 'module', 'text/typescript', 'Presentation layer module boundary.', apiProfile),
|
|
306
|
+
artifact('src/presentation/rest/rest.presentation.module.ts', 'presentation', 'source', 'module', 'text/typescript', 'REST channel module boundary.', apiProfile),
|
|
307
|
+
artifact('src/presentation/rest/auth/auth.module.ts', 'presentation', 'source', 'module', 'text/typescript', 'REST auth module registering controllers, guards, and decorators.', apiProfile),
|
|
308
|
+
artifact('src/presentation/rest/auth/controllers/register.controller.ts', 'presentation', 'source', 'controller', 'text/typescript', 'Swagger-documented REST controller that injects an application input port.', apiProfile),
|
|
309
|
+
artifact('src/presentation/rest/auth/dtos/register-input.dto.ts', 'presentation', 'source', 'dto', 'text/typescript', 'Swagger-documented REST input DTO for a user-facing route.', apiProfile),
|
|
310
|
+
artifact('src/presentation/rest/auth/dtos/auth-session-output.dto.ts', 'presentation', 'source', 'dto', 'text/typescript', 'Swagger-documented REST output DTO for session responses.', apiProfile),
|
|
311
|
+
artifact('src/presentation/rest/auth/guards/jwt-auth.guard.ts', 'presentation', 'source', 'implementation', 'text/typescript', 'REST route guard baseline for protected bearer routes.', apiProfile),
|
|
312
|
+
artifact('src/presentation/rest/auth/guards/permission.guard.ts', 'presentation', 'source', 'implementation', 'text/typescript', 'REST authorization guard baseline for permission-protected routes.', apiProfile),
|
|
313
|
+
artifact('src/presentation/rest/auth/decorators/permission.decorator.ts', 'presentation', 'source', 'policy', 'text/typescript', 'REST authorization decorator baseline for permission metadata.', apiProfile),
|
|
314
|
+
artifact('src/presentation/dtos/api-error-response.dto.ts', 'presentation', 'source', 'dto', 'text/typescript', 'Swagger-documented error response DTO for controller response metadata.', apiProfile),
|
|
315
|
+
artifact('src/presentation/graphql/graphql.presentation.module.ts', 'presentation', 'source', 'module', 'text/typescript', 'GraphQL channel module boundary.', apiProfile),
|
|
316
|
+
artifact('src/presentation/cli/cli.presentation.module.ts', 'presentation', 'source', 'module', 'text/typescript', 'CLI channel module boundary.', apiProfile),
|
|
317
|
+
artifact('src/presentation/websocket/websocket.module.ts', 'presentation', 'source', 'module', 'text/typescript', 'WebSocket channel module boundary.', apiProfile),
|
|
318
|
+
artifact('src/shared/domain/generic-business-object.ts', 'shared', 'source', 'abstraction', 'text/typescript', 'Shared domain primitive used by Foundation packages.', apiProfile),
|
|
319
|
+
artifact('src/shared/presentation/generic-controller.ts', 'shared', 'source', 'abstraction', 'text/typescript', 'Shared presentation primitive used by REST controllers.', apiProfile),
|
|
320
|
+
artifact('tests/app.e2e-spec.ts', 'tests', 'test', 'test', 'text/typescript', 'Initial E2E smoke test for the generated API scaffold.', apiProfile),
|
|
321
|
+
artifact('tests/jest-e2e.json', 'tests', 'configuration', 'manifest', 'application/json', 'Jest E2E configuration for the scaffold.', apiProfile),
|
|
244
322
|
];
|
|
323
|
+
const plannedPaths = new Set(baselineArtifacts.map((entry) => entry.path));
|
|
324
|
+
const profileOverlayArtifacts = getCodeSddApiProfileDryRunExpectation(apiProfile).expected_writes
|
|
325
|
+
.filter((expectedWrite) => !plannedPaths.has(expectedWrite.path))
|
|
326
|
+
.map((expectedWrite) => artifact(expectedWrite.path, expectedWrite.layer, expectedWrite.artifact_kind, expectedWrite.role, contentTypeForScaffoldPath(expectedWrite.path, expectedWrite.artifact_kind), `${expectedWrite.reason} (Profile overlay for ${apiProfile}.)`, apiProfile));
|
|
327
|
+
return [...baselineArtifacts, ...profileOverlayArtifacts];
|
|
245
328
|
}
|
|
246
|
-
function
|
|
329
|
+
function contentTypeForScaffoldPath(artifactPath, artifactKind) {
|
|
330
|
+
if (artifactPath.endsWith('.ts')) {
|
|
331
|
+
return 'text/typescript';
|
|
332
|
+
}
|
|
333
|
+
if (artifactPath.endsWith('.json')) {
|
|
334
|
+
return 'application/json';
|
|
335
|
+
}
|
|
336
|
+
if (artifactPath.endsWith('.md')) {
|
|
337
|
+
return 'text/markdown';
|
|
338
|
+
}
|
|
339
|
+
if (artifactPath.endsWith('.yaml') || artifactPath.endsWith('.yml')) {
|
|
340
|
+
return 'text/yaml';
|
|
341
|
+
}
|
|
342
|
+
if (artifactKind === 'documentation') {
|
|
343
|
+
return 'text/markdown';
|
|
344
|
+
}
|
|
345
|
+
return 'text/plain';
|
|
346
|
+
}
|
|
347
|
+
function artifact(artifactPath, layer, artifactKind, role, contentType, reason, apiProfile) {
|
|
247
348
|
const mapEntry = {
|
|
248
349
|
path: artifactPath,
|
|
249
350
|
layer,
|
|
@@ -256,7 +357,7 @@ function artifact(artifactPath, layer, artifactKind, role, contentType, reason)
|
|
|
256
357
|
implementation: role === 'interface' || role === 'repository-port' ? 'contract' : 'generated',
|
|
257
358
|
decision_refs: ['EPIC-0075'],
|
|
258
359
|
source_refs: [`${DEVTRACK_API_REFERENCE_ROOT}/${artifactPath}`],
|
|
259
|
-
tags: ['devtrack-api', 'foundation-api'],
|
|
360
|
+
tags: ['devtrack-api', 'foundation-api', 'codesdd-api-profile', apiProfile],
|
|
260
361
|
metadata: {},
|
|
261
362
|
};
|
|
262
363
|
return {
|
|
@@ -277,4 +378,7 @@ function normalizePackageName(value) {
|
|
|
277
378
|
}
|
|
278
379
|
return normalized;
|
|
279
380
|
}
|
|
381
|
+
function unique(values) {
|
|
382
|
+
return [...new Set(values)];
|
|
383
|
+
}
|
|
280
384
|
//# sourceMappingURL=devtrack-api-appliance.js.map
|
|
@@ -24,6 +24,22 @@ export interface DevTrackApiArchitectureValidationResult {
|
|
|
24
24
|
architecture_schema: QualityArchitectureSchema;
|
|
25
25
|
import_graph: QualityImportGraph;
|
|
26
26
|
findings: DevTrackApiArchitectureFinding[];
|
|
27
|
+
drift_signals: DevTrackApiDriftSignal[];
|
|
28
|
+
profile_outcomes: DevTrackApiProfileOutcome[];
|
|
29
|
+
}
|
|
30
|
+
export type DevTrackApiDriftClass = 'CVD-01' | 'CVD-02' | 'CVD-03' | 'CVD-04' | 'CVD-05' | 'CVD-06' | 'CVD-07' | 'CVD-08' | 'CVD-09' | 'WCA-01' | 'WCA-02' | 'WCA-03';
|
|
31
|
+
export interface DevTrackApiDriftSignal {
|
|
32
|
+
drift_class: DevTrackApiDriftClass;
|
|
33
|
+
observed: string;
|
|
34
|
+
mapped_rules: string[];
|
|
35
|
+
finding_codes: DevTrackApiArchitectureIssueCode[];
|
|
36
|
+
}
|
|
37
|
+
export interface DevTrackApiProfileOutcome {
|
|
38
|
+
profile: 'prototype' | 'foundation-compatible' | 'enterprise-strict';
|
|
39
|
+
status: 'passed' | 'warning' | 'blocked';
|
|
40
|
+
blocking_rules: string[];
|
|
41
|
+
blocking_drift_classes: DevTrackApiDriftClass[];
|
|
42
|
+
exception_candidate_rules: string[];
|
|
27
43
|
}
|
|
28
44
|
export declare function buildDevTrackApiArchitectureSchema(): QualityArchitectureSchema;
|
|
29
45
|
export declare function collectDevTrackApiImportGraph(input: CollectDevTrackApiImportGraphInput): Promise<QualityImportGraph>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
3
4
|
import ts from 'typescript';
|
|
5
|
+
import { parse as parseYaml } from 'yaml';
|
|
4
6
|
import { parseQualityArchitectureSchema, } from './quality-validation.js';
|
|
5
7
|
export const DEVTRACK_API_ARCHITECTURE_SCHEMA_ID = 'ARCH-GATE-devtrack-api-p0';
|
|
6
8
|
const DEFAULT_SOURCE_ROOTS = ['src', 'prisma'];
|
|
@@ -17,6 +19,30 @@ const DEVTRACK_ALIAS_PREFIXES = [
|
|
|
17
19
|
'@shared/',
|
|
18
20
|
'@src/',
|
|
19
21
|
];
|
|
22
|
+
const DEVTRACK_API_CONTRACT_PACK_PATH = fileURLToPath(new URL('../../../.sdd/skills/curated/devtrack-api/references/contract-pack.yaml', import.meta.url));
|
|
23
|
+
const DRIFT_CLASS_TO_FINDING_CODES = {
|
|
24
|
+
'CVD-02': [
|
|
25
|
+
'ARCH_RELATIVE_IMPORT_FORBIDDEN',
|
|
26
|
+
'ARCH_APPLICATION_PRESENTATION_IMPORT',
|
|
27
|
+
'ARCH_APPLICATION_CONCRETE_INFRA_IMPORT',
|
|
28
|
+
'ARCH_PRESENTATION_INFRA_IMPORT',
|
|
29
|
+
'ARCH_TYPEORM_IMPORT_OUTSIDE_INFRASTRUCTURE',
|
|
30
|
+
'ARCH_TYPEORM_ENTITY_PATH_INVALID',
|
|
31
|
+
'ARCH_TYPEORM_ENTITY_SUFFIX_INVALID',
|
|
32
|
+
'ARCH_TYPEORM_REPOSITORY_PATH_INVALID',
|
|
33
|
+
'ARCH_TYPEORM_REPOSITORY_SUFFIX_INVALID',
|
|
34
|
+
'ARCH_PRESENTATION_TRANSPORT_MISSING',
|
|
35
|
+
'ARCH_INFRASTRUCTURE_CONTEXT_PERSISTENCE_FORBIDDEN',
|
|
36
|
+
],
|
|
37
|
+
'CVD-03': ['ARCH_TYPEORM_REPOSITORY_FAKE'],
|
|
38
|
+
'CVD-04': ['ARCH_PRESENTATION_COMPOSITION_ROOT', 'ARCH_AGGREGATE_MODULE_MISSING', 'ARCH_AGGREGATE_MODULE_NOT_NESTJS'],
|
|
39
|
+
'CVD-05': ['ARCH_PORT_MISSING_SYMBOL', 'ARCH_PORT_GROUPED_UNRELATED'],
|
|
40
|
+
'CVD-06': ['ARCH_BO_MISSING_METHODS', 'ARCH_VO_MISSING_METHODS'],
|
|
41
|
+
'CVD-07': ['ARCH_MISSING_DATASOURCE', 'ARCH_MISSING_MIGRATIONS', 'ARCH_MISSING_TYPEORM_MODULE_FORFEATURE'],
|
|
42
|
+
'CVD-09': ['ARCH_DOMAIN_REPOSITORY_PORT_CONTEXT_FORBIDDEN'],
|
|
43
|
+
'WCA-02': ['ARCH_RELATIVE_IMPORT_FORBIDDEN'],
|
|
44
|
+
'WCA-03': ['ARCH_TYPEORM_REPOSITORY_FAKE', 'ARCH_MISSING_TYPEORM_MODULE_FORFEATURE'],
|
|
45
|
+
};
|
|
20
46
|
export function buildDevTrackApiArchitectureSchema() {
|
|
21
47
|
return parseQualityArchitectureSchema({
|
|
22
48
|
schema_version: 1,
|
|
@@ -157,13 +183,73 @@ export async function validateDevTrackApiArchitecture(input) {
|
|
|
157
183
|
detectMissingAggregateModules(files, fileContents, findings);
|
|
158
184
|
detectMissingRuntimePersistence(files, fileContents, findings);
|
|
159
185
|
const dedupedFindings = dedupeFindings(findings);
|
|
186
|
+
const contractPack = await loadDevTrackApiContractPack();
|
|
187
|
+
const driftSignals = mapFindingsToDriftSignals(dedupedFindings, contractPack);
|
|
188
|
+
const profileOutcomes = buildProfileOutcomes(driftSignals, contractPack);
|
|
160
189
|
return {
|
|
161
190
|
status: dedupedFindings.length > 0 ? 'warning' : 'passed',
|
|
162
191
|
architecture_schema: buildDevTrackApiArchitectureSchema(),
|
|
163
192
|
import_graph: importGraph,
|
|
164
193
|
findings: dedupedFindings,
|
|
194
|
+
drift_signals: driftSignals,
|
|
195
|
+
profile_outcomes: profileOutcomes,
|
|
165
196
|
};
|
|
166
197
|
}
|
|
198
|
+
async function loadDevTrackApiContractPack() {
|
|
199
|
+
const raw = await fs.readFile(DEVTRACK_API_CONTRACT_PACK_PATH, 'utf-8');
|
|
200
|
+
return parseYaml(raw);
|
|
201
|
+
}
|
|
202
|
+
function mapFindingsToDriftSignals(findings, contractPack) {
|
|
203
|
+
const findingCodes = new Set(findings.map((finding) => finding.code));
|
|
204
|
+
const driftSignals = [];
|
|
205
|
+
for (const [driftClass, mappedFindingCodes] of Object.entries(DRIFT_CLASS_TO_FINDING_CODES)) {
|
|
206
|
+
const matchedCodes = mappedFindingCodes.filter((code) => findingCodes.has(code));
|
|
207
|
+
if (matchedCodes.length === 0)
|
|
208
|
+
continue;
|
|
209
|
+
const mapping = contractPack.codesdd_validate_drift_map[driftClass] ?? contractPack.field_evidence_drift_map[driftClass];
|
|
210
|
+
driftSignals.push({
|
|
211
|
+
drift_class: driftClass,
|
|
212
|
+
observed: mapping?.observed ?? 'Observed semantic drift mapped from validator findings.',
|
|
213
|
+
mapped_rules: [...new Set(mapping?.mapped_rules ?? [])],
|
|
214
|
+
finding_codes: matchedCodes,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return driftSignals.sort((left, right) => left.drift_class.localeCompare(right.drift_class));
|
|
218
|
+
}
|
|
219
|
+
function buildProfileOutcomes(driftSignals, contractPack) {
|
|
220
|
+
const ruleSeverity = new Map(contractPack.rules.map((rule) => [rule.id, rule.severity]));
|
|
221
|
+
const ruleIds = [...new Set(driftSignals.flatMap((signal) => signal.mapped_rules))];
|
|
222
|
+
const p0Rules = ruleIds.filter((ruleId) => ruleSeverity.get(ruleId) === 'P0');
|
|
223
|
+
const p1Rules = ruleIds.filter((ruleId) => ruleSeverity.get(ruleId) === 'P1');
|
|
224
|
+
const p2Rules = ruleIds.filter((ruleId) => ruleSeverity.get(ruleId) === 'P2');
|
|
225
|
+
return [
|
|
226
|
+
{
|
|
227
|
+
profile: 'prototype',
|
|
228
|
+
status: driftSignals.length > 0 ? 'warning' : 'passed',
|
|
229
|
+
blocking_rules: [],
|
|
230
|
+
blocking_drift_classes: [],
|
|
231
|
+
exception_candidate_rules: [],
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
profile: 'foundation-compatible',
|
|
235
|
+
status: p0Rules.length > 0 ? 'blocked' : driftSignals.length > 0 ? 'warning' : 'passed',
|
|
236
|
+
blocking_rules: p0Rules,
|
|
237
|
+
blocking_drift_classes: driftSignals
|
|
238
|
+
.filter((signal) => signal.mapped_rules.some((ruleId) => p0Rules.includes(ruleId)))
|
|
239
|
+
.map((signal) => signal.drift_class),
|
|
240
|
+
exception_candidate_rules: [...new Set([...p1Rules, ...p2Rules])],
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
profile: 'enterprise-strict',
|
|
244
|
+
status: p0Rules.length > 0 || p1Rules.length > 0 ? 'blocked' : driftSignals.length > 0 ? 'warning' : 'passed',
|
|
245
|
+
blocking_rules: [...new Set([...p0Rules, ...p1Rules])],
|
|
246
|
+
blocking_drift_classes: driftSignals
|
|
247
|
+
.filter((signal) => signal.mapped_rules.some((ruleId) => p0Rules.includes(ruleId) || p1Rules.includes(ruleId)))
|
|
248
|
+
.map((signal) => signal.drift_class),
|
|
249
|
+
exception_candidate_rules: p2Rules,
|
|
250
|
+
},
|
|
251
|
+
];
|
|
252
|
+
}
|
|
167
253
|
function finding(code, filePath, importSpecifier, message, remediation) {
|
|
168
254
|
return {
|
|
169
255
|
code,
|
|
@@ -53,7 +53,7 @@ Initial operational directives:
|
|
|
53
53
|
- CodeSDD is the official planner for any build request; other planners or agent-native plans are secondary execution aids only.
|
|
54
54
|
- In initialized CodeSDD repositories, any user request that implies implementation, file edits, validation, execution, or finalize must be treated as requiring CodeSDD planning unless the user explicitly marks it as read-only or outside CodeSDD.
|
|
55
55
|
- For change requests, agents must bind the work to an active or ready FEAT through \`${CLI_NAME} sdd next\` and \`${CLI_NAME} sdd context <FEAT-ID>\` before implementation; agent-native plans may only decompose execution after that CodeSDD context exists.
|
|
56
|
-
- For API/backend work,
|
|
56
|
+
- For API/backend work, select a CodeSDD API profile (\`minimal-rest\`, \`rest-auth-rbac\`, \`rest-crud-typeorm\`, \`evented-api\`, \`ai-agent-api\`, or \`full-foundation-compatible\`); \`devtrack-api\` remains the compatibility skill/alias and Python/Flask API work stays routed to \`api-clean-flask-langgraph\`.
|
|
57
57
|
- During init, onboard, insight, and debate flows, CodeSDD-managed agent instruction blocks must be inspected and reconfigured when they drift from this contract.
|
|
58
58
|
- Commit requests must follow Conventional Commits, selective staging, and grouping by modified directory plus change protocol (\`src\`, \`${memoryDir}\`, docs, config, infra, dependencies, or generated files).
|
|
59
59
|
|
|
@@ -116,7 +116,7 @@ Initial directives:
|
|
|
116
116
|
- CodeSDD is the official planner for requested work; model-native plans and other planning tools are subordinate to CodeSDD artifacts.
|
|
117
117
|
- In initialized CodeSDD repositories, implementation, edit, validation, execution, and finalize requests implicitly require CodeSDD planning unless the user explicitly marks the request as read-only or outside CodeSDD.
|
|
118
118
|
- A change request must use the active or ready FEAT returned by \`${CLI_NAME} sdd next\` and must load \`${CLI_NAME} sdd context <FEAT-ID>\` before coding; model-native plans may only refine execution after that context exists.
|
|
119
|
-
- API/backend work
|
|
119
|
+
- API/backend work selects a CodeSDD API profile (\`minimal-rest\`, \`rest-auth-rbac\`, \`rest-crud-typeorm\`, \`evented-api\`, \`ai-agent-api\`, or \`full-foundation-compatible\`); \`devtrack-api\` remains the compatibility skill/alias, and Python/Flask API work uses \`api-clean-flask-langgraph\`.
|
|
120
120
|
- CodeSDD-managed blocks in \`AGENTS.md\`, \`AGENT.md\`, \`CLAUDE.md\`, \`GEMINI.md\`, \`.codex\`, \`.opencode\`, \`.ai\`, \`.cloud\`, or equivalent agent files must be inspected and normalized during init/onboard/insight/debate when CodeSDD owns project governance.
|
|
121
121
|
- Commits must use Conventional Commits, selective staging, and grouping by modified directory plus protocol: source, \`${memoryDir}\`, docs, config, infra, dependencies, generated files, renames, or deletions.`;
|
|
122
122
|
}
|
|
@@ -150,7 +150,7 @@ Initial directives:
|
|
|
150
150
|
- CodeSDD is the official planner. Other planning systems may assist execution only after CodeSDD context exists.
|
|
151
151
|
- In initialized CodeSDD repositories, implementation, edit, validation, execution, and finalize requests implicitly require CodeSDD planning unless the user explicitly marks the request as read-only or outside CodeSDD.
|
|
152
152
|
- Agents must bind each change request to the active or ready FEAT returned by \`${CLI_NAME} sdd next\` and load \`${CLI_NAME} sdd context <FEAT-ID>\` before coding.
|
|
153
|
-
- API/backend work
|
|
153
|
+
- API/backend work selects a CodeSDD API profile (\`minimal-rest\`, \`rest-auth-rbac\`, \`rest-crud-typeorm\`, \`evented-api\`, \`ai-agent-api\`, or \`full-foundation-compatible\`); \`devtrack-api\` remains the compatibility skill/alias, and Python/Flask API work remains a documented exception routed to \`api-clean-flask-langgraph\`.
|
|
154
154
|
- CodeSDD lifecycle entrypoints must inspect and normalize CodeSDD-managed agent instruction blocks in root and tool-specific agent files.
|
|
155
155
|
- Commit work must use Conventional Commits, selective staging, and directory/protocol grouping. Source changes, \`${memoryDir}\` governance, docs, config, infra, dependencies, generated files, renames, and deletions should be staged and committed separately unless indivisible.`;
|
|
156
156
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ArtifactAllocatorLease } from './artifact-id-allocator.js';
|
|
2
|
+
import type { EnterpriseProvisioningPolicyReport } from './enterprise-provisioning-policy.js';
|
|
3
|
+
export type EnterpriseCommandGateDecision = 'allow' | 'block' | 'bypass-detected';
|
|
4
|
+
export interface EnterpriseMutatingCommandGateRequest {
|
|
5
|
+
command: string;
|
|
6
|
+
mutates_numbered_artifacts: boolean;
|
|
7
|
+
provisioning: EnterpriseProvisioningPolicyReport;
|
|
8
|
+
project_id?: string;
|
|
9
|
+
tenant_id?: string;
|
|
10
|
+
artifact_type?: ArtifactAllocatorLease['artifact_type'];
|
|
11
|
+
lease?: ArtifactAllocatorLease;
|
|
12
|
+
fencing_token?: number;
|
|
13
|
+
now: string;
|
|
14
|
+
bypass_requested?: boolean;
|
|
15
|
+
bypass_reason?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface EnterpriseMutatingCommandGateResult {
|
|
18
|
+
decision: EnterpriseCommandGateDecision;
|
|
19
|
+
reason: string;
|
|
20
|
+
required: boolean;
|
|
21
|
+
bypass_detected: boolean;
|
|
22
|
+
requested_mode: 'local' | 'enterprise';
|
|
23
|
+
effective_mode: 'local' | 'enterprise';
|
|
24
|
+
local_mode_exception_accepted: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function evaluateEnterpriseMutatingCommandGate(request: EnterpriseMutatingCommandGateRequest): EnterpriseMutatingCommandGateResult;
|
|
27
|
+
//# sourceMappingURL=enterprise-mutating-command-gate.d.ts.map
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { validateAllocatorFencingToken } from './artifact-id-allocator.js';
|
|
2
|
+
export function evaluateEnterpriseMutatingCommandGate(request) {
|
|
3
|
+
const requestedMode = request.provisioning.requested_mode ?? request.provisioning.mode;
|
|
4
|
+
const effectiveMode = request.provisioning.effective_mode ??
|
|
5
|
+
(request.provisioning.requested && request.provisioning.status !== 'disabled' ? 'enterprise' : 'local');
|
|
6
|
+
const localModeExceptionAccepted = request.provisioning.local_mode_exception_accepted ??
|
|
7
|
+
(!request.provisioning.requested || request.provisioning.status === 'disabled');
|
|
8
|
+
if (!request.mutates_numbered_artifacts) {
|
|
9
|
+
return {
|
|
10
|
+
decision: 'allow',
|
|
11
|
+
reason: `Command ${request.command} does not mutate numbered artifacts.`,
|
|
12
|
+
required: false,
|
|
13
|
+
bypass_detected: false,
|
|
14
|
+
requested_mode: requestedMode,
|
|
15
|
+
effective_mode: effectiveMode,
|
|
16
|
+
local_mode_exception_accepted: localModeExceptionAccepted,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (request.bypass_requested) {
|
|
20
|
+
return {
|
|
21
|
+
decision: 'bypass-detected',
|
|
22
|
+
reason: request.bypass_reason
|
|
23
|
+
? `Bypass requested for ${request.command}: ${request.bypass_reason}`
|
|
24
|
+
: `Bypass requested for ${request.command} without an auditable reason.`,
|
|
25
|
+
required: true,
|
|
26
|
+
bypass_detected: true,
|
|
27
|
+
requested_mode: requestedMode,
|
|
28
|
+
effective_mode: effectiveMode,
|
|
29
|
+
local_mode_exception_accepted: localModeExceptionAccepted,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (!request.provisioning.requested || request.provisioning.status === 'disabled') {
|
|
33
|
+
return {
|
|
34
|
+
decision: 'allow',
|
|
35
|
+
reason: 'Enterprise provisioning is not requested for this mutation; local mode exception is accepted and numbered artifact mutation is allowed.',
|
|
36
|
+
required: false,
|
|
37
|
+
bypass_detected: false,
|
|
38
|
+
requested_mode: requestedMode,
|
|
39
|
+
effective_mode: 'local',
|
|
40
|
+
local_mode_exception_accepted: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (request.provisioning.status !== 'ready') {
|
|
44
|
+
return {
|
|
45
|
+
decision: 'block',
|
|
46
|
+
reason: `Enterprise provisioning is ${request.provisioning.status} with requested_mode=${requestedMode} and effective_mode=enterprise: ` +
|
|
47
|
+
request.provisioning.reason,
|
|
48
|
+
required: true,
|
|
49
|
+
bypass_detected: false,
|
|
50
|
+
requested_mode: requestedMode,
|
|
51
|
+
effective_mode: 'enterprise',
|
|
52
|
+
local_mode_exception_accepted: false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (!request.lease || request.fencing_token === undefined) {
|
|
56
|
+
return {
|
|
57
|
+
decision: 'block',
|
|
58
|
+
reason: `Command ${request.command} requires an active allocator lease and fencing token in Enterprise mode.`,
|
|
59
|
+
required: true,
|
|
60
|
+
bypass_detected: false,
|
|
61
|
+
requested_mode: requestedMode,
|
|
62
|
+
effective_mode: 'enterprise',
|
|
63
|
+
local_mode_exception_accepted: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if ((request.project_id !== undefined && request.lease.project_id !== request.project_id) ||
|
|
67
|
+
(request.tenant_id !== undefined && request.lease.tenant_id !== request.tenant_id) ||
|
|
68
|
+
(request.artifact_type !== undefined && request.lease.artifact_type !== request.artifact_type)) {
|
|
69
|
+
return {
|
|
70
|
+
decision: 'block',
|
|
71
|
+
reason: `Command ${request.command} allocator lease scope does not match the requested mutation scope.`,
|
|
72
|
+
required: true,
|
|
73
|
+
bypass_detected: false,
|
|
74
|
+
requested_mode: requestedMode,
|
|
75
|
+
effective_mode: 'enterprise',
|
|
76
|
+
local_mode_exception_accepted: false,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const fencing = validateAllocatorFencingToken(request.lease, {
|
|
80
|
+
fencing_token: request.fencing_token,
|
|
81
|
+
now: request.now,
|
|
82
|
+
});
|
|
83
|
+
if (!fencing.valid) {
|
|
84
|
+
return {
|
|
85
|
+
decision: 'block',
|
|
86
|
+
reason: `Command ${request.command} allocator fencing token is ${fencing.reason}.`,
|
|
87
|
+
required: true,
|
|
88
|
+
bypass_detected: false,
|
|
89
|
+
requested_mode: requestedMode,
|
|
90
|
+
effective_mode: 'enterprise',
|
|
91
|
+
local_mode_exception_accepted: false,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
decision: 'allow',
|
|
96
|
+
reason: `Command ${request.command} has a valid Enterprise allocator lease and fencing token.`,
|
|
97
|
+
required: true,
|
|
98
|
+
bypass_detected: false,
|
|
99
|
+
requested_mode: requestedMode,
|
|
100
|
+
effective_mode: 'enterprise',
|
|
101
|
+
local_mode_exception_accepted: false,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=enterprise-mutating-command-gate.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ArtifactIdAllocatorState } from './artifact-id-allocator.js';
|
|
2
|
+
export interface EnterpriseProvenanceFinding {
|
|
3
|
+
severity: 'blocker' | 'warning';
|
|
4
|
+
code: string;
|
|
5
|
+
message: string;
|
|
6
|
+
ref?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface EnterpriseProvenanceReport {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
findings: EnterpriseProvenanceFinding[];
|
|
11
|
+
counters: {
|
|
12
|
+
reservations: number;
|
|
13
|
+
leases: number;
|
|
14
|
+
canonical_writes: number;
|
|
15
|
+
drafts: number;
|
|
16
|
+
audit_events: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare function evaluateEnterpriseAllocatorProvenance(state: ArtifactIdAllocatorState): EnterpriseProvenanceReport;
|
|
20
|
+
//# sourceMappingURL=enterprise-provenance-gates.d.ts.map
|