import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import { parseDeploymentProfileYaml, validateDeploymentProfileSchema, generateDeploymentProfileArtifact, generateDeploymentProfileArtifactFromFile, } from '../src/storage/profile-generator.mjs'; import { validateDeploymentProfileArtifact } from '../src/storage/profile-artifact.mjs'; const packageRoot = path.resolve(import.meta.dirname, '..'); const repoRoot = path.resolve(packageRoot, '..', '..'); const complexProfileYaml = `apiVersion: reporting-governance/v1alpha1 kind: DeploymentProfile metadata: id: demo version: 1.0.0 runtime: openclaw title: Demo Profile summary: >- Complex profile for YAML parser coverage with nested objects, arrays, and folded scalars. spec: package: pluginVersion: 0.1.0-mainline compatibility: adapterInterface: reporting-governance-adapter-interface deploymentModel: reporting-governance-deployment-model policies: enabledPacks: - no-silence - verified-completion-only overrides: completion: minQuality: moderate checkpoints: overdueAction: force_checkpoint escalationAfterMisses: 2 adapters: hook: enabled: true watchdog: enabled: true scheduleMode: cron queue: enabled: true dispatcher: enabled: true bridge: enabled: true truthfulDeliveryStates: - dispatched - acked sender: mode: openclaw-cli orchestrator: enabled: true notifications: operatorVisibleRecoveryRequired: true allowedTerminalStates: - acked - blocked audit: portableArtifactsRequired: true requiredArtifacts: - canonical_events - queue_items - bridge_receipts - profile_snapshot capability_expectations: required: - create_queue_items preferred: - direct_sender_binding `; test('deployment profile yaml parser reads strict-manager-mode profile shape', () => { const artifact = generateDeploymentProfileArtifactFromFile(path.join(packageRoot, 'profiles-src', 'strict-manager-mode.yaml')); assert.equal(artifact.metadata.id, 'strict-manager-mode'); assert.equal(artifact.metadata.runtime, 'openclaw'); assert.equal(artifact.spec.package.pluginVersion, '0.1.0-mainline'); assert.equal(artifact.metadata.source_profile, 'profiles-src/strict-manager-mode.yaml'); }); test('deployment profile schema validator rejects malformed profile', () => { assert.throws( () => validateDeploymentProfileSchema({ kind: 'DeploymentProfile' }), /deployment profile schema validation failed: .*missing required property apiVersion/ ); assert.throws( () => validateDeploymentProfileSchema({ apiVersion: 'reporting-governance/v1alpha1', kind: 'DeploymentProfile', metadata: { id: 'x', version: '1.0.0', runtime: 'openclaw' }, spec: { package: { pluginVersion: 7 }, adapters: { hook: { enabled: true }, watchdog: { enabled: true }, queue: { enabled: true }, dispatcher: { enabled: true }, bridge: { enabled: true }, sender: { mode: 'openclaw-cli' }, orchestrator: { enabled: true }, }, notifications: { operatorVisibleRecoveryRequired: true, allowedTerminalStates: ['acked'], }, audit: { portableArtifactsRequired: true, requiredArtifacts: ['canonical_events', 'queue_items', 'bridge_receipts'] }, capability_expectations: { required: [] }, }, }), /deployment profile schema validation failed: .*\/spec\/package\/pluginVersion must be string/ ); }); test('deployment profile schema validator rejects tightened semantic violations', () => { const validBase = { apiVersion: 'reporting-governance/v1alpha1', kind: 'DeploymentProfile', metadata: { id: 'strict', version: '1.0.0', runtime: 'openclaw' }, spec: { package: { pluginVersion: '0.1.0-mainline' }, adapters: { hook: { enabled: true }, watchdog: { enabled: true }, queue: { enabled: true }, dispatcher: { enabled: true }, bridge: { enabled: true }, sender: { mode: 'openclaw-cli' }, orchestrator: { enabled: true }, }, notifications: { operatorVisibleRecoveryRequired: true, allowedTerminalStates: ['acked'], }, audit: { portableArtifactsRequired: true, requiredArtifacts: ['canonical_events', 'queue_items', 'bridge_receipts'], }, capability_expectations: { required: [] }, }, }; assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: true, requiredArtifacts: [], }, }, }), /deployment profile schema validation failed: .*\/spec\/audit\/requiredArtifacts must NOT have fewer than 1 items/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, notifications: { operatorVisibleRecoveryRequired: 'yes', allowedTerminalStates: ['acked'], }, }, }), /deployment profile schema validation failed: .*\/spec\/notifications\/operatorVisibleRecoveryRequired must be boolean/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, notifications: { operatorVisibleRecoveryRequired: true, allowedTerminalStates: ['done'], }, }, }), /deployment profile schema validation failed: .*\/spec\/notifications\/allowedTerminalStates\/0 must be equal to one of the allowed values/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: 'true', requiredArtifacts: ['canonical_events', 'queue_items', 'bridge_receipts'], }, }, }), /deployment profile schema validation failed: .*\/spec\/audit\/portableArtifactsRequired must be boolean/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, notifications: { operatorVisibleRecoveryRequired: true, allowedTerminalStates: [], }, }, }), /deployment profile schema validation failed: .*\/spec\/notifications\/allowedTerminalStates must NOT have fewer than 1 items/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, notifications: { operatorVisibleRecoveryRequired: true, allowedTerminalStates: ['acked', 'acked'], }, }, }), /deployment profile schema validation failed: .*\/spec\/notifications\/allowedTerminalStates must NOT have duplicate items/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: true, requiredArtifacts: ['canonical_events', 'queue_items', 'queue_items', 'bridge_receipts'], }, }, }), /deployment profile schema validation failed: .*\/spec\/audit\/requiredArtifacts must NOT have duplicate items/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: true, requiredArtifacts: ['queue_items', 'bridge_receipts'], }, }, }), /deployment profile schema validation failed: .*\/spec\/audit\/requiredArtifacts must contain at least 1 valid item\(s\)/ ); assert.doesNotThrow(() => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: false, requiredArtifacts: ['queue_items', 'bridge_receipts'], }, }, }) ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: false, requiredArtifacts: [], }, }, }), /deployment profile schema validation failed: .*\/spec\/audit\/requiredArtifacts must NOT have fewer than 1 items/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: true, requiredArtifacts: ['canonical_events', 'queue_items', 'bridge_receipts', 'made_up_artifact'], }, }, }), /deployment profile schema validation failed: .*\/spec\/audit\/requiredArtifacts\/3 must be equal to one of the allowed values/ ); assert.doesNotThrow(() => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, audit: { portableArtifactsRequired: false, requiredArtifacts: ['canonical_events'], }, }, }) ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, adapters: { ...validBase.spec.adapters, queue: { enabled: 'true' }, }, }, }), /deployment profile schema validation failed: .*\/spec\/adapters\/queue\/enabled must be boolean/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, adapters: { ...validBase.spec.adapters, sender: { mode: 'shim' }, }, }, }), /deployment profile schema validation failed: .*\/spec\/adapters\/sender\/mode must be equal to one of the allowed values/ ); assert.throws( () => validateDeploymentProfileSchema({ ...validBase, spec: { ...validBase.spec, adapters: { watchdog: { enabled: true }, queue: { enabled: true }, dispatcher: { enabled: true }, bridge: { enabled: true }, sender: { mode: 'openclaw-cli' }, orchestrator: { enabled: true }, }, }, }), /deployment profile schema validation failed: .*\/spec\/adapters missing required property hook/ ); }); test('deployment profile yaml parser covers composite nested yaml structure', () => { const profile = parseDeploymentProfileYaml(complexProfileYaml); assert.equal(profile.metadata.summary, 'Complex profile for YAML parser coverage with nested objects, arrays, and folded scalars.'); assert.deepEqual(profile.spec.policies.enabledPacks, ['no-silence', 'verified-completion-only']); assert.equal(profile.spec.policies.overrides.checkpoints.overdueAction, 'force_checkpoint'); assert.deepEqual(profile.spec.adapters.bridge.truthfulDeliveryStates, ['dispatched', 'acked']); assert.deepEqual(profile.spec.notifications.allowedTerminalStates, ['acked', 'blocked']); }); test('yaml to artifact generation produces validator-compatible package artifact', () => { const profile = parseDeploymentProfileYaml(complexProfileYaml); const artifact = generateDeploymentProfileArtifact(profile, { sourceProfile: 'profiles/demo.yaml' }); assert.equal(artifact.kind, 'DeploymentProfileArtifact'); assert.equal(artifact.metadata.source_profile, 'profiles/demo.yaml'); assert.equal(artifact.spec.bindings.entrypoint, 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'); assert.doesNotThrow(() => validateDeploymentProfileArtifact(artifact)); }); test('strict-manager YAML generation matches checked-in package artifact snapshot', () => { const generated = generateDeploymentProfileArtifactFromFile(path.join(packageRoot, 'profiles-src', 'strict-manager-mode.yaml')); const checkedIn = validateDeploymentProfileArtifact( JSON.parse( fs.readFileSync( path.join(packageRoot, 'profiles', 'strict-manager-mode.profile.json'), 'utf8' ) ) ); assert.deepEqual(generated, checkedIn); }); test('profile artifact generator CLI exits 1 with actionable error on malformed profile', () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'reporting-governance-profile-cli-')); const malformedProfilePath = path.join(tempDir, 'malformed.yaml'); const outputArtifactPath = path.join(tempDir, 'artifact.json'); fs.writeFileSync(malformedProfilePath, `apiVersion: reporting-governance/v1alpha1 kind: DeploymentProfile metadata: id: malformed version: 1.0.0 runtime: openclaw spec: package: pluginVersion: 123 adapters: hook: enabled: true watchdog: enabled: true queue: enabled: true dispatcher: enabled: true bridge: enabled: true sender: mode: openclaw-cli orchestrator: enabled: true notifications: operatorVisibleRecoveryRequired: true allowedTerminalStates: - acked audit: portableArtifactsRequired: true requiredArtifacts: - canonical_events - queue_items - bridge_receipts capability_expectations: required: [] `, 'utf8'); const result = spawnSync( process.execPath, [path.join(repoRoot, 'scripts', 'generate_reporting_governance_profile_artifact.mjs'), malformedProfilePath, outputArtifactPath], { encoding: 'utf8' } ); assert.equal(result.status, 1); assert.match(result.stderr, /profile artifact generation failed:/); assert.match(result.stderr, /deployment profile schema validation failed:/); assert.match(result.stderr, /\/spec\/package\/pluginVersion must be string/); assert.equal(fs.existsSync(outputArtifactPath), false); });