@a5c-ai/krate 5.0.1-staging.00fa5317c
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/Dockerfile +31 -0
- package/README.md +183 -0
- package/bin/krate-demo.mjs +23 -0
- package/bin/krate-server.mjs +14 -0
- package/dist/krate-controller-ui.json +3205 -0
- package/dist/krate-lifecycle.json +201 -0
- package/dist/krate-runtime-snapshot.json +3125 -0
- package/dist/krate-summary.json +724 -0
- package/docs/README.md +61 -0
- package/docs/agents/README.md +83 -0
- package/docs/agents/acceptance-test-matrix.md +193 -0
- package/docs/agents/agent-mux-adapter-contract.md +167 -0
- package/docs/agents/agent-mux-source-map.md +310 -0
- package/docs/agents/agent-run-memory-import-spec.md +256 -0
- package/docs/agents/agent-stack-management-spec.md +421 -0
- package/docs/agents/api-contract-spec.md +309 -0
- package/docs/agents/artifacts-writeback-spec.md +145 -0
- package/docs/agents/chart-packaging-spec.md +128 -0
- package/docs/agents/ci-orchestration-spec.md +140 -0
- package/docs/agents/context-assembly-spec.md +219 -0
- package/docs/agents/controller-reconciliation-spec.md +255 -0
- package/docs/agents/crd-schema-spec.md +315 -0
- package/docs/agents/decision-log-open-questions.md +169 -0
- package/docs/agents/developer-implementation-checklist.md +329 -0
- package/docs/agents/dispatching-design.md +262 -0
- package/docs/agents/gaps-agent-mux-to-krate-crds.md +298 -0
- package/docs/agents/glossary.md +66 -0
- package/docs/agents/implementation-blueprint.md +324 -0
- package/docs/agents/implementation-rollout-slices.md +251 -0
- package/docs/agents/memory-context-integration-spec.md +194 -0
- package/docs/agents/memory-ontology-schema-spec.md +253 -0
- package/docs/agents/memory-operations-runbook.md +121 -0
- package/docs/agents/mvp-vertical-slice-spec.md +146 -0
- package/docs/agents/observability-audit-spec.md +265 -0
- package/docs/agents/operator-runbook.md +174 -0
- package/docs/agents/org-memory-api-payload-examples.md +333 -0
- package/docs/agents/org-memory-controller-sequence-spec.md +181 -0
- package/docs/agents/org-memory-e2e-fixture-plan.md +161 -0
- package/docs/agents/org-memory-ui-implementation-map.md +114 -0
- package/docs/agents/org-memory-vertical-slice-spec.md +168 -0
- package/docs/agents/org-resource-model-delta-spec.md +111 -0
- package/docs/agents/org-route-resource-model-spec.md +183 -0
- package/docs/agents/org-scoping-namespace-spec.md +114 -0
- package/docs/agents/rbac-secrets-management-spec.md +406 -0
- package/docs/agents/repository-page-integration-spec.md +255 -0
- package/docs/agents/resource-contract-examples.md +808 -0
- package/docs/agents/resource-relationship-map.md +190 -0
- package/docs/agents/security-threat-model.md +188 -0
- package/docs/agents/shared-memory-company-brain-spec.md +358 -0
- package/docs/agents/storage-migration-spec.md +168 -0
- package/docs/agents/subagent-orchestration-spec.md +152 -0
- package/docs/agents/system-overview.md +88 -0
- package/docs/agents/tools-mcp-skills-spec.md +189 -0
- package/docs/agents/traceability-matrix.md +79 -0
- package/docs/agents/ui-flow-spec.md +211 -0
- package/docs/agents/ui-ux-system-spec.md +426 -0
- package/docs/agents/workspace-lifecycle-spec.md +166 -0
- package/docs/architecture-spec.md +78 -0
- package/docs/components/control-plane.md +78 -0
- package/docs/components/data-plane.md +69 -0
- package/docs/components/hooks-events.md +67 -0
- package/docs/components/identity-rbac-policy.md +73 -0
- package/docs/components/kubevela-oam.md +70 -0
- package/docs/components/operations-publishing.md +81 -0
- package/docs/components/runners-ci.md +66 -0
- package/docs/components/web-ui.md +94 -0
- package/docs/external/README.md +47 -0
- package/docs/external/bidirectional-sync-design.md +134 -0
- package/docs/external/cicd-interface.md +64 -0
- package/docs/external/external-backend-controllers.md +170 -0
- package/docs/external/external-backend-crds.md +234 -0
- package/docs/external/external-backend-ui-spec.md +151 -0
- package/docs/external/external-backend-ux-flows.md +115 -0
- package/docs/external/external-object-mapping.md +125 -0
- package/docs/external/git-forge-interface.md +68 -0
- package/docs/external/github-integration-design.md +151 -0
- package/docs/external/issue-tracking-interface.md +66 -0
- package/docs/external/provider-capability-manifests.md +204 -0
- package/docs/external/provider-catalog.md +139 -0
- package/docs/external/provider-rollout-testing.md +78 -0
- package/docs/external/research-results.md +48 -0
- package/docs/external/security-auth-permissions.md +81 -0
- package/docs/external/sync-state-machines.md +108 -0
- package/docs/external/unified-external-backend-model.md +107 -0
- package/docs/external/user-facing-changes.md +67 -0
- package/docs/gaps.md +161 -0
- package/docs/install.md +94 -0
- package/docs/krate-design.md +334 -0
- package/docs/local-minikube.md +55 -0
- package/docs/ontology/README.md +32 -0
- package/docs/ontology/bounded-contexts.md +29 -0
- package/docs/ontology/events-and-hooks.md +32 -0
- package/docs/ontology/oam-kubevela.md +32 -0
- package/docs/ontology/operations-and-release.md +25 -0
- package/docs/ontology/personas-and-actors.md +32 -0
- package/docs/ontology/policies-and-invariants.md +33 -0
- package/docs/ontology/problem-space.md +30 -0
- package/docs/ontology/resource-contracts.md +40 -0
- package/docs/ontology/resource-taxonomy.md +42 -0
- package/docs/ontology/runners-and-ci.md +29 -0
- package/docs/ontology/solution-space.md +24 -0
- package/docs/ontology/storage-and-data-boundaries.md +29 -0
- package/docs/ontology/validation-matrix.md +24 -0
- package/docs/ontology/web-ui-excellent-flows.md +32 -0
- package/docs/ontology/workflows.md +39 -0
- package/docs/ontology/world.md +35 -0
- package/docs/openapi.yaml +1275 -0
- package/docs/product-requirements.md +62 -0
- package/docs/roadmap-mvp.md +87 -0
- package/docs/system-requirements.md +90 -0
- package/docs/tests/README.md +53 -0
- package/docs/tests/agent-qa-plan.md +63 -0
- package/docs/tests/browser-ui-tests.md +62 -0
- package/docs/tests/ci-quality-gates.md +48 -0
- package/docs/tests/coverage-model.md +64 -0
- package/docs/tests/e2e-scenario-tests.md +53 -0
- package/docs/tests/fixtures-test-data.md +63 -0
- package/docs/tests/observability-reliability-tests.md +54 -0
- package/docs/tests/product-test-matrix.md +145 -0
- package/docs/tests/qa-adoption-roadmap.md +130 -0
- package/docs/tests/qa-automation-plan.md +101 -0
- package/docs/tests/security-compliance-tests.md +57 -0
- package/docs/tests/test-framework-tools.md +88 -0
- package/docs/tests/test-suite-layout.md +121 -0
- package/docs/tests/unit-integration-tests.md +48 -0
- package/docs/todo-kyverno +714 -0
- package/docs/todos.md +4 -0
- package/docs/user-stories.md +78 -0
- package/examples/minikube-demo.yaml +190 -0
- package/examples/oam-application.yaml +23 -0
- package/examples/policy-kyverno-pr-title.yaml +18 -0
- package/package.json +63 -0
- package/scripts/build.mjs +29 -0
- package/scripts/setup-minikube.mjs +65 -0
- package/scripts/smoke.mjs +37 -0
- package/scripts/validate-doc-coverage.mjs +152 -0
- package/scripts/validate-package.mjs +93 -0
- package/scripts/validate-ui.mjs +278 -0
- package/src/agent-adapter-controller.js +169 -0
- package/src/agent-approval-controller.js +170 -0
- package/src/agent-context-bundles.js +242 -0
- package/src/agent-dispatch-controller.js +209 -0
- package/src/agent-gateway-config-controller.js +147 -0
- package/src/agent-memory-controller.js +357 -0
- package/src/agent-memory-import.js +327 -0
- package/src/agent-memory-query.js +292 -0
- package/src/agent-memory-repository-source-controller.js +255 -0
- package/src/agent-mux-client.js +280 -0
- package/src/agent-permission-review.js +250 -0
- package/src/agent-project-controller.js +117 -0
- package/src/agent-provider-config-controller.js +150 -0
- package/src/agent-secret-config-grant-controller.js +282 -0
- package/src/agent-session-transcript-controller.js +189 -0
- package/src/agent-stack-controller.js +347 -0
- package/src/agent-subagent-controller.js +160 -0
- package/src/agent-transport-binding-controller.js +121 -0
- package/src/agent-trigger-controller.js +381 -0
- package/src/agent-workspace-controller.js +702 -0
- package/src/agent-writeback-controller.js +302 -0
- package/src/api-controller.js +541 -0
- package/src/argocd-gitops.js +43 -0
- package/src/async-controller.js +207 -0
- package/src/audit-controller.js +191 -0
- package/src/auth.js +307 -0
- package/src/component-catalog.js +41 -0
- package/src/control-plane.js +136 -0
- package/src/controller-client.js +72 -0
- package/src/controller-ui.js +617 -0
- package/src/data-plane.js +179 -0
- package/src/event-bus.js +61 -0
- package/src/external/conflict-controller.js +225 -0
- package/src/external/github/auth.js +96 -0
- package/src/external/github/cicd.js +180 -0
- package/src/external/github/git-forge.js +240 -0
- package/src/external/github/index.js +144 -0
- package/src/external/github/issue-tracking.js +163 -0
- package/src/external/provider-adapter.js +161 -0
- package/src/external/provider-resource-factory.js +161 -0
- package/src/external/sync-controller.js +235 -0
- package/src/external/webhook-controller.js +144 -0
- package/src/external/write-controller.js +283 -0
- package/src/gitea-backend.js +131 -0
- package/src/gitea-service.js +173 -0
- package/src/handoff.js +98 -0
- package/src/hooks-events.js +63 -0
- package/src/http-server.js +377 -0
- package/src/identity-policy.js +86 -0
- package/src/index.js +57 -0
- package/src/kubernetes-controller-async.js +511 -0
- package/src/kubernetes-controller.js +878 -0
- package/src/kubernetes-resource-gateway.js +48 -0
- package/src/notification-controller.js +178 -0
- package/src/operations.js +112 -0
- package/src/org-scoping.js +5 -0
- package/src/resource-model.js +221 -0
- package/src/runner-controller.js +272 -0
- package/src/runners-ci.js +48 -0
- package/src/runtime.js +196 -0
- package/src/snapshot-cache.js +157 -0
- package/src/web-ui.js +40 -0
- package/tests/agent-adapter-controller.test.js +361 -0
- package/tests/agent-approval-controller.test.js +173 -0
- package/tests/agent-context-bundles.test.js +278 -0
- package/tests/agent-dispatch-controller.test.js +315 -0
- package/tests/agent-gateway-config-controller.test.js +386 -0
- package/tests/agent-memory-controller.test.js +308 -0
- package/tests/agent-memory-import-snapshot.test.js +477 -0
- package/tests/agent-memory-query.test.js +404 -0
- package/tests/agent-memory-repository-source.test.js +514 -0
- package/tests/agent-mux-client.test.js +204 -0
- package/tests/agent-permission-review-v2.test.js +317 -0
- package/tests/agent-permission-review.test.js +209 -0
- package/tests/agent-project-controller.test.js +302 -0
- package/tests/agent-provider-config-controller.test.js +376 -0
- package/tests/agent-resources.test.js +228 -0
- package/tests/agent-secret-config-grant.test.js +231 -0
- package/tests/agent-session-transcript-controller.test.js +499 -0
- package/tests/agent-stack-controller.test.js +221 -0
- package/tests/agent-subagent-controller.test.js +201 -0
- package/tests/agent-transport-binding-controller.test.js +294 -0
- package/tests/agent-trigger-controller.test.js +211 -0
- package/tests/agent-trigger-routes.test.js +190 -0
- package/tests/agent-trigger-sources.test.js +245 -0
- package/tests/agent-workspace-controller.test.js +181 -0
- package/tests/agent-writeback.test.js +292 -0
- package/tests/approval-persistence.test.js +171 -0
- package/tests/async-controller.test.js +252 -0
- package/tests/audit-controller.test.js +227 -0
- package/tests/codespace-controller.test.js +318 -0
- package/tests/deployment.test.js +407 -0
- package/tests/e2e/lifecycle.test.js +117 -0
- package/tests/event-bus-integration.test.js +190 -0
- package/tests/external-github-forge.test.js +560 -0
- package/tests/external-github-issues-cicd.test.js +520 -0
- package/tests/external-integration.test.js +470 -0
- package/tests/external-persistence.test.js +340 -0
- package/tests/external-provider-adapter.test.js +365 -0
- package/tests/external-resource-model.test.js +215 -0
- package/tests/external-webhook-sync.test.js +287 -0
- package/tests/external-write-conflict.test.js +353 -0
- package/tests/gitea-service.test.js +253 -0
- package/tests/health-check-real.test.js +165 -0
- package/tests/integration/full-flow.test.js +266 -0
- package/tests/krate.test.js +756 -0
- package/tests/memory-search-wiring.test.js +270 -0
- package/tests/notification-controller.test.js +196 -0
- package/tests/notification-integration.test.js +179 -0
- package/tests/org-scoping.test.js +687 -0
- package/tests/runner-controller.test.js +327 -0
- package/tests/runner-integration.test.js +231 -0
- package/tests/session-cookie-hmac.test.js +151 -0
- package/tests/snapshot-performance.test.js +247 -0
- package/tests/sse-events.test.js +107 -0
- package/tests/webhook-trigger.test.js +198 -0
- package/tests/workspace-volumes.test.js +312 -0
- package/tests/writeback-persistence.test.js +207 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
// Slice 2.3a — AgentMemoryRepository & AgentMemorySource Controllers
|
|
2
|
+
// TDD: tests written BEFORE implementation.
|
|
3
|
+
//
|
|
4
|
+
// AgentMemoryRepository: org-level memory storage pointer, git repo ref validation.
|
|
5
|
+
// AgentMemorySource: read policies for memory paths, access control.
|
|
6
|
+
|
|
7
|
+
import assert from 'node:assert/strict';
|
|
8
|
+
import test from 'node:test';
|
|
9
|
+
import {
|
|
10
|
+
createResource,
|
|
11
|
+
validateMemoryRepository,
|
|
12
|
+
validateMemorySource,
|
|
13
|
+
createAgentMemoryRepositoryController,
|
|
14
|
+
createAgentMemorySourceController,
|
|
15
|
+
AGENT_MEMORY_REPOSITORY_CONTROLLER_BOUNDARY,
|
|
16
|
+
AGENT_MEMORY_SOURCE_CONTROLLER_BOUNDARY,
|
|
17
|
+
} from '../src/index.js';
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Helpers
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
function makeMemoryRepository(name, overrides = {}) {
|
|
24
|
+
return createResource('AgentMemoryRepository', { name, namespace: 'krate-org-default' }, {
|
|
25
|
+
organizationRef: 'acme',
|
|
26
|
+
repositoryRef: 'company-brain',
|
|
27
|
+
defaultBranch: 'main',
|
|
28
|
+
layoutProfile: 'standard',
|
|
29
|
+
repoUrl: 'https://github.com/acme/company-brain.git',
|
|
30
|
+
...overrides,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function makeMemorySource(name, overrides = {}) {
|
|
35
|
+
return createResource('AgentMemorySource', { name, namespace: 'krate-org-default' }, {
|
|
36
|
+
organizationRef: 'acme',
|
|
37
|
+
repositoryRef: 'company-brain',
|
|
38
|
+
appliesTo: { kind: 'AgentStack', name: 'my-stack' },
|
|
39
|
+
include: { paths: ['docs/**', 'records/**'] },
|
|
40
|
+
paths: ['docs/**', 'records/**'],
|
|
41
|
+
...overrides,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ===========================================================================
|
|
46
|
+
// AgentMemoryRepository — controller factory
|
|
47
|
+
// ===========================================================================
|
|
48
|
+
|
|
49
|
+
test('createAgentMemoryRepositoryController returns controller with expected methods', () => {
|
|
50
|
+
const controller = createAgentMemoryRepositoryController();
|
|
51
|
+
assert.ok(controller, 'controller must be truthy');
|
|
52
|
+
assert.equal(typeof controller.validateMemoryRepository, 'function', 'must expose validateMemoryRepository');
|
|
53
|
+
assert.equal(typeof controller.getRepositoryUrl, 'function', 'must expose getRepositoryUrl');
|
|
54
|
+
assert.equal(typeof controller.getRetentionPolicy, 'function', 'must expose getRetentionPolicy');
|
|
55
|
+
assert.equal(controller.role, 'agent-memory-repository-controller', 'must declare its role');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// validateMemoryRepository — happy path
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
test('validateMemoryRepository accepts valid config with name, orgRef, and repoUrl', () => {
|
|
63
|
+
const controller = createAgentMemoryRepositoryController();
|
|
64
|
+
const repo = makeMemoryRepository('brain-repo');
|
|
65
|
+
|
|
66
|
+
const result = controller.validateMemoryRepository(repo);
|
|
67
|
+
|
|
68
|
+
assert.equal(result.valid, true, 'valid config must pass validation');
|
|
69
|
+
assert.ok(Array.isArray(result.errors), 'result must contain an errors array');
|
|
70
|
+
assert.equal(result.errors.length, 0, 'errors array must be empty for a valid config');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// validateMemoryRepository — missing name
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
test('validateMemoryRepository rejects missing name', () => {
|
|
78
|
+
const controller = createAgentMemoryRepositoryController();
|
|
79
|
+
const repo = {
|
|
80
|
+
apiVersion: 'krate.a5c.ai/v1alpha1',
|
|
81
|
+
kind: 'AgentMemoryRepository',
|
|
82
|
+
metadata: { namespace: 'krate-org-default', labels: {}, annotations: {} },
|
|
83
|
+
spec: {
|
|
84
|
+
organizationRef: 'acme',
|
|
85
|
+
repositoryRef: 'company-brain',
|
|
86
|
+
defaultBranch: 'main',
|
|
87
|
+
layoutProfile: 'standard',
|
|
88
|
+
repoUrl: 'https://github.com/acme/brain.git',
|
|
89
|
+
},
|
|
90
|
+
status: {},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const result = controller.validateMemoryRepository(repo);
|
|
94
|
+
|
|
95
|
+
assert.equal(result.valid, false, 'missing name must fail validation');
|
|
96
|
+
assert.ok(result.errors.length > 0, 'errors must not be empty');
|
|
97
|
+
assert.ok(
|
|
98
|
+
result.errors.some((e) => /name/i.test(e)),
|
|
99
|
+
'at least one error must mention "name"'
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// validateMemoryRepository — missing repoUrl
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
test('validateMemoryRepository rejects missing repoUrl', () => {
|
|
108
|
+
const controller = createAgentMemoryRepositoryController();
|
|
109
|
+
const repo = makeMemoryRepository('no-url-repo');
|
|
110
|
+
delete repo.spec.repoUrl;
|
|
111
|
+
|
|
112
|
+
const result = controller.validateMemoryRepository(repo);
|
|
113
|
+
|
|
114
|
+
assert.equal(result.valid, false, 'missing repoUrl must fail validation');
|
|
115
|
+
assert.ok(result.errors.length > 0, 'errors must not be empty');
|
|
116
|
+
assert.ok(
|
|
117
|
+
result.errors.some((e) => /repoUrl/i.test(e)),
|
|
118
|
+
'at least one error must mention "repoUrl"'
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// validateMemoryRepository — invalid repoUrl (not git/http/ssh URL)
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
test('validateMemoryRepository rejects invalid repoUrl (not git/http/ssh URL)', () => {
|
|
127
|
+
const controller = createAgentMemoryRepositoryController();
|
|
128
|
+
const repo = makeMemoryRepository('bad-url-repo', { repoUrl: 'ftp://not-a-git-url.example.com/repo' });
|
|
129
|
+
|
|
130
|
+
const result = controller.validateMemoryRepository(repo);
|
|
131
|
+
|
|
132
|
+
assert.equal(result.valid, false, 'invalid repoUrl protocol must fail validation');
|
|
133
|
+
assert.ok(result.errors.length > 0, 'errors must not be empty');
|
|
134
|
+
assert.ok(
|
|
135
|
+
result.errors.some((e) => /repoUrl/i.test(e)),
|
|
136
|
+
'at least one error must mention "repoUrl"'
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('validateMemoryRepository accepts git+ssh URL (git@ format)', () => {
|
|
141
|
+
const controller = createAgentMemoryRepositoryController();
|
|
142
|
+
const repo = makeMemoryRepository('ssh-repo', { repoUrl: 'git@github.com:acme/company-brain.git' });
|
|
143
|
+
|
|
144
|
+
const result = controller.validateMemoryRepository(repo);
|
|
145
|
+
|
|
146
|
+
assert.equal(result.valid, true, 'git@host:path.git URL must pass validation');
|
|
147
|
+
assert.equal(result.errors.length, 0, 'errors must be empty for valid git ssh URL');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('validateMemoryRepository accepts ssh:// URL', () => {
|
|
151
|
+
const controller = createAgentMemoryRepositoryController();
|
|
152
|
+
const repo = makeMemoryRepository('ssh-proto-repo', { repoUrl: 'ssh://git@github.com/acme/brain.git' });
|
|
153
|
+
|
|
154
|
+
const result = controller.validateMemoryRepository(repo);
|
|
155
|
+
|
|
156
|
+
assert.equal(result.valid, true, 'ssh:// URL must pass validation');
|
|
157
|
+
assert.equal(result.errors.length, 0, 'errors must be empty for valid ssh:// URL');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
// getRepositoryUrl — returns configured URL
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
test('getRepositoryUrl returns the configured repoUrl from spec', () => {
|
|
165
|
+
const controller = createAgentMemoryRepositoryController();
|
|
166
|
+
const repo = makeMemoryRepository('url-repo', { repoUrl: 'https://github.com/acme/brain.git' });
|
|
167
|
+
|
|
168
|
+
const url = controller.getRepositoryUrl(repo);
|
|
169
|
+
|
|
170
|
+
assert.equal(url, 'https://github.com/acme/brain.git', 'must return spec repoUrl');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('getRepositoryUrl throws on null resource', () => {
|
|
174
|
+
const controller = createAgentMemoryRepositoryController();
|
|
175
|
+
|
|
176
|
+
assert.throws(
|
|
177
|
+
() => controller.getRepositoryUrl(null),
|
|
178
|
+
/null|undefined/i,
|
|
179
|
+
'getRepositoryUrl must throw on null resource'
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// getRetentionPolicy — returns retention config with defaults
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
test('getRetentionPolicy returns retention config with defaults (maxAgeDays: 90, maxSizeMb: 500)', () => {
|
|
188
|
+
const controller = createAgentMemoryRepositoryController();
|
|
189
|
+
const repo = makeMemoryRepository('retention-repo');
|
|
190
|
+
|
|
191
|
+
const policy = controller.getRetentionPolicy(repo);
|
|
192
|
+
|
|
193
|
+
assert.ok(policy, 'getRetentionPolicy must return a value');
|
|
194
|
+
assert.equal(policy.maxAgeDays, 90, 'default maxAgeDays must be 90');
|
|
195
|
+
assert.equal(policy.maxSizeMb, 500, 'default maxSizeMb must be 500');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('getRetentionPolicy merges spec retentionPolicy with defaults', () => {
|
|
199
|
+
const controller = createAgentMemoryRepositoryController();
|
|
200
|
+
const repo = makeMemoryRepository('custom-retention-repo', {
|
|
201
|
+
retentionPolicy: { maxAgeDays: 180, maxSizeMb: 1000 },
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const policy = controller.getRetentionPolicy(repo);
|
|
205
|
+
|
|
206
|
+
assert.equal(policy.maxAgeDays, 180, 'spec maxAgeDays must override default');
|
|
207
|
+
assert.equal(policy.maxSizeMb, 1000, 'spec maxSizeMb must override default');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test('getRetentionPolicy throws on null resource', () => {
|
|
211
|
+
const controller = createAgentMemoryRepositoryController();
|
|
212
|
+
|
|
213
|
+
assert.throws(
|
|
214
|
+
() => controller.getRetentionPolicy(null),
|
|
215
|
+
/null|undefined/i,
|
|
216
|
+
'getRetentionPolicy must throw on null resource'
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
// validateMemoryRepository — rejects null resource
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
test('validateMemoryRepository rejects null resource', () => {
|
|
225
|
+
const controller = createAgentMemoryRepositoryController();
|
|
226
|
+
|
|
227
|
+
const result = controller.validateMemoryRepository(null);
|
|
228
|
+
|
|
229
|
+
assert.equal(result.valid, false, 'null resource must fail validation');
|
|
230
|
+
assert.ok(result.errors.length > 0, 'errors must not be empty');
|
|
231
|
+
assert.ok(
|
|
232
|
+
result.errors.some((e) => /null|undefined/i.test(e)),
|
|
233
|
+
'error must mention null or undefined'
|
|
234
|
+
);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
// validateMemoryRepository standalone export
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
|
|
241
|
+
test('validateMemoryRepository standalone export follows existing pattern', () => {
|
|
242
|
+
assert.equal(typeof validateMemoryRepository, 'function', 'validateMemoryRepository must be a named export');
|
|
243
|
+
|
|
244
|
+
const repo = makeMemoryRepository('standalone-validate-repo');
|
|
245
|
+
const result = validateMemoryRepository(repo);
|
|
246
|
+
|
|
247
|
+
assert.ok(result, 'must return a result');
|
|
248
|
+
assert.ok('valid' in result, 'result must have a valid property');
|
|
249
|
+
assert.ok(Array.isArray(result.errors), 'result must have an errors array');
|
|
250
|
+
assert.equal(result.valid, true, 'a fully-specified repo must pass standalone validation');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
// BOUNDARY — AgentMemoryRepository
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
test('AGENT_MEMORY_REPOSITORY_CONTROLLER_BOUNDARY is exported with correct role', () => {
|
|
258
|
+
assert.ok(AGENT_MEMORY_REPOSITORY_CONTROLLER_BOUNDARY, 'BOUNDARY must be exported');
|
|
259
|
+
assert.equal(
|
|
260
|
+
AGENT_MEMORY_REPOSITORY_CONTROLLER_BOUNDARY.role,
|
|
261
|
+
'agent-memory-repository-controller',
|
|
262
|
+
'BOUNDARY role must be "agent-memory-repository-controller"'
|
|
263
|
+
);
|
|
264
|
+
assert.ok(
|
|
265
|
+
Array.isArray(AGENT_MEMORY_REPOSITORY_CONTROLLER_BOUNDARY.owns),
|
|
266
|
+
'BOUNDARY must declare owned concerns'
|
|
267
|
+
);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// ===========================================================================
|
|
271
|
+
// AgentMemorySource — controller factory
|
|
272
|
+
// ===========================================================================
|
|
273
|
+
|
|
274
|
+
test('createAgentMemorySourceController returns controller with expected methods', () => {
|
|
275
|
+
const controller = createAgentMemorySourceController();
|
|
276
|
+
assert.ok(controller, 'controller must be truthy');
|
|
277
|
+
assert.equal(typeof controller.validateMemorySource, 'function', 'must expose validateMemorySource');
|
|
278
|
+
assert.equal(typeof controller.getReadPolicy, 'function', 'must expose getReadPolicy');
|
|
279
|
+
assert.equal(typeof controller.getIncludedPaths, 'function', 'must expose getIncludedPaths');
|
|
280
|
+
assert.equal(typeof controller.getExcludedPaths, 'function', 'must expose getExcludedPaths');
|
|
281
|
+
assert.equal(controller.role, 'agent-memory-source-controller', 'must declare its role');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
// validateMemorySource — happy path
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
test('validateMemorySource accepts valid config (name, orgRef, repositoryRef, paths)', () => {
|
|
289
|
+
const controller = createAgentMemorySourceController();
|
|
290
|
+
const source = makeMemorySource('good-source');
|
|
291
|
+
|
|
292
|
+
const result = controller.validateMemorySource(source);
|
|
293
|
+
|
|
294
|
+
assert.equal(result.valid, true, 'valid config must pass validation');
|
|
295
|
+
assert.ok(Array.isArray(result.errors), 'result must contain an errors array');
|
|
296
|
+
assert.equal(result.errors.length, 0, 'errors array must be empty for a valid config');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
// validateMemorySource — missing repositoryRef
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
|
|
303
|
+
test('validateMemorySource rejects missing repositoryRef', () => {
|
|
304
|
+
const controller = createAgentMemorySourceController();
|
|
305
|
+
const source = makeMemorySource('no-repo-source');
|
|
306
|
+
delete source.spec.repositoryRef;
|
|
307
|
+
|
|
308
|
+
const result = controller.validateMemorySource(source);
|
|
309
|
+
|
|
310
|
+
assert.equal(result.valid, false, 'missing repositoryRef must fail validation');
|
|
311
|
+
assert.ok(result.errors.length > 0, 'errors must not be empty');
|
|
312
|
+
assert.ok(
|
|
313
|
+
result.errors.some((e) => /repositoryRef/i.test(e)),
|
|
314
|
+
'at least one error must mention "repositoryRef"'
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
// validateMemorySource — empty paths array
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
test('validateMemorySource rejects empty paths array', () => {
|
|
323
|
+
const controller = createAgentMemorySourceController();
|
|
324
|
+
const source = makeMemorySource('empty-paths-source', { paths: [] });
|
|
325
|
+
|
|
326
|
+
const result = controller.validateMemorySource(source);
|
|
327
|
+
|
|
328
|
+
assert.equal(result.valid, false, 'empty paths must fail validation');
|
|
329
|
+
assert.ok(result.errors.length > 0, 'errors must not be empty');
|
|
330
|
+
assert.ok(
|
|
331
|
+
result.errors.some((e) => /paths/i.test(e)),
|
|
332
|
+
'at least one error must mention "paths"'
|
|
333
|
+
);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// ---------------------------------------------------------------------------
|
|
337
|
+
// validateMemorySource — rejects null resource
|
|
338
|
+
// ---------------------------------------------------------------------------
|
|
339
|
+
|
|
340
|
+
test('validateMemorySource rejects null resource', () => {
|
|
341
|
+
const controller = createAgentMemorySourceController();
|
|
342
|
+
|
|
343
|
+
const result = controller.validateMemorySource(null);
|
|
344
|
+
|
|
345
|
+
assert.equal(result.valid, false, 'null resource must fail validation');
|
|
346
|
+
assert.ok(result.errors.length > 0, 'errors must not be empty');
|
|
347
|
+
assert.ok(
|
|
348
|
+
result.errors.some((e) => /null|undefined/i.test(e)),
|
|
349
|
+
'error must mention null or undefined'
|
|
350
|
+
);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// ---------------------------------------------------------------------------
|
|
354
|
+
// getReadPolicy — returns access policy with defaults
|
|
355
|
+
// ---------------------------------------------------------------------------
|
|
356
|
+
|
|
357
|
+
test('getReadPolicy returns access policy from spec with defaults', () => {
|
|
358
|
+
const controller = createAgentMemorySourceController();
|
|
359
|
+
const source = makeMemorySource('policy-source');
|
|
360
|
+
|
|
361
|
+
const policy = controller.getReadPolicy(source);
|
|
362
|
+
|
|
363
|
+
assert.ok(policy, 'getReadPolicy must return a value');
|
|
364
|
+
assert.ok('mode' in policy, 'policy must include a mode');
|
|
365
|
+
assert.ok('maxDepth' in policy, 'policy must include a maxDepth default');
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test('getReadPolicy merges spec readPolicy with defaults', () => {
|
|
369
|
+
const controller = createAgentMemorySourceController();
|
|
370
|
+
const source = makeMemorySource('custom-policy-source', {
|
|
371
|
+
readPolicy: { mode: 'allow-list', maxDepth: 3 },
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
const policy = controller.getReadPolicy(source);
|
|
375
|
+
|
|
376
|
+
assert.equal(policy.mode, 'allow-list', 'spec mode must override default');
|
|
377
|
+
assert.equal(policy.maxDepth, 3, 'spec maxDepth must override default');
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test('getReadPolicy throws on null resource', () => {
|
|
381
|
+
const controller = createAgentMemorySourceController();
|
|
382
|
+
|
|
383
|
+
assert.throws(
|
|
384
|
+
() => controller.getReadPolicy(null),
|
|
385
|
+
/null|undefined/i,
|
|
386
|
+
'getReadPolicy must throw on null resource'
|
|
387
|
+
);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// ---------------------------------------------------------------------------
|
|
391
|
+
// getIncludedPaths — returns the paths array
|
|
392
|
+
// ---------------------------------------------------------------------------
|
|
393
|
+
|
|
394
|
+
test('getIncludedPaths returns the paths array from spec', () => {
|
|
395
|
+
const controller = createAgentMemorySourceController();
|
|
396
|
+
const source = makeMemorySource('paths-source', { paths: ['docs/**', 'records/**', 'ontology/**'] });
|
|
397
|
+
|
|
398
|
+
const paths = controller.getIncludedPaths(source);
|
|
399
|
+
|
|
400
|
+
assert.ok(Array.isArray(paths), 'getIncludedPaths must return an array');
|
|
401
|
+
assert.equal(paths.length, 3, 'must return all 3 paths');
|
|
402
|
+
assert.ok(paths.includes('docs/**'), 'must include docs/**');
|
|
403
|
+
assert.ok(paths.includes('records/**'), 'must include records/**');
|
|
404
|
+
assert.ok(paths.includes('ontology/**'), 'must include ontology/**');
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test('getIncludedPaths throws on null resource', () => {
|
|
408
|
+
const controller = createAgentMemorySourceController();
|
|
409
|
+
|
|
410
|
+
assert.throws(
|
|
411
|
+
() => controller.getIncludedPaths(null),
|
|
412
|
+
/null|undefined/i,
|
|
413
|
+
'getIncludedPaths must throw on null resource'
|
|
414
|
+
);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// ---------------------------------------------------------------------------
|
|
418
|
+
// getExcludedPaths — returns excluded paths or empty array
|
|
419
|
+
// ---------------------------------------------------------------------------
|
|
420
|
+
|
|
421
|
+
test('getExcludedPaths returns empty array when no excludedPaths in spec', () => {
|
|
422
|
+
const controller = createAgentMemorySourceController();
|
|
423
|
+
const source = makeMemorySource('no-exclude-source');
|
|
424
|
+
|
|
425
|
+
const excluded = controller.getExcludedPaths(source);
|
|
426
|
+
|
|
427
|
+
assert.ok(Array.isArray(excluded), 'getExcludedPaths must return an array');
|
|
428
|
+
assert.equal(excluded.length, 0, 'must return empty array when no excludedPaths set');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
test('getExcludedPaths returns excluded paths from spec', () => {
|
|
432
|
+
const controller = createAgentMemorySourceController();
|
|
433
|
+
const source = makeMemorySource('exclude-source', {
|
|
434
|
+
excludedPaths: ['secrets/**', 'tmp/**'],
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
const excluded = controller.getExcludedPaths(source);
|
|
438
|
+
|
|
439
|
+
assert.ok(Array.isArray(excluded), 'getExcludedPaths must return an array');
|
|
440
|
+
assert.equal(excluded.length, 2, 'must return both excluded paths');
|
|
441
|
+
assert.ok(excluded.includes('secrets/**'), 'must include secrets/**');
|
|
442
|
+
assert.ok(excluded.includes('tmp/**'), 'must include tmp/**');
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test('getExcludedPaths throws on null resource', () => {
|
|
446
|
+
const controller = createAgentMemorySourceController();
|
|
447
|
+
|
|
448
|
+
assert.throws(
|
|
449
|
+
() => controller.getExcludedPaths(null),
|
|
450
|
+
/null|undefined/i,
|
|
451
|
+
'getExcludedPaths must throw on null resource'
|
|
452
|
+
);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// ---------------------------------------------------------------------------
|
|
456
|
+
// validateMemorySource standalone export
|
|
457
|
+
// ---------------------------------------------------------------------------
|
|
458
|
+
|
|
459
|
+
test('validateMemorySource standalone export follows existing pattern', () => {
|
|
460
|
+
assert.equal(typeof validateMemorySource, 'function', 'validateMemorySource must be a named export');
|
|
461
|
+
|
|
462
|
+
const source = makeMemorySource('standalone-validate-source');
|
|
463
|
+
const result = validateMemorySource(source);
|
|
464
|
+
|
|
465
|
+
assert.ok(result, 'must return a result');
|
|
466
|
+
assert.ok('valid' in result, 'result must have a valid property');
|
|
467
|
+
assert.ok(Array.isArray(result.errors), 'result must have an errors array');
|
|
468
|
+
assert.equal(result.valid, true, 'a fully-specified source must pass standalone validation');
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// ---------------------------------------------------------------------------
|
|
472
|
+
// BOUNDARY — AgentMemorySource
|
|
473
|
+
// ---------------------------------------------------------------------------
|
|
474
|
+
|
|
475
|
+
test('AGENT_MEMORY_SOURCE_CONTROLLER_BOUNDARY is exported with correct role', () => {
|
|
476
|
+
assert.ok(AGENT_MEMORY_SOURCE_CONTROLLER_BOUNDARY, 'BOUNDARY must be exported');
|
|
477
|
+
assert.equal(
|
|
478
|
+
AGENT_MEMORY_SOURCE_CONTROLLER_BOUNDARY.role,
|
|
479
|
+
'agent-memory-source-controller',
|
|
480
|
+
'BOUNDARY role must be "agent-memory-source-controller"'
|
|
481
|
+
);
|
|
482
|
+
assert.ok(
|
|
483
|
+
Array.isArray(AGENT_MEMORY_SOURCE_CONTROLLER_BOUNDARY.owns),
|
|
484
|
+
'BOUNDARY must declare owned concerns'
|
|
485
|
+
);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// ---------------------------------------------------------------------------
|
|
489
|
+
// validate — accumulates multiple errors (source)
|
|
490
|
+
// ---------------------------------------------------------------------------
|
|
491
|
+
|
|
492
|
+
test('validateMemorySource accumulates all errors when multiple fields are invalid', () => {
|
|
493
|
+
const controller = createAgentMemorySourceController();
|
|
494
|
+
const source = {
|
|
495
|
+
apiVersion: 'krate.a5c.ai/v1alpha1',
|
|
496
|
+
kind: 'AgentMemorySource',
|
|
497
|
+
metadata: { namespace: 'krate-org-default', labels: {}, annotations: {} },
|
|
498
|
+
spec: { organizationRef: 'acme', appliesTo: {}, include: {} },
|
|
499
|
+
status: {},
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
const result = controller.validateMemorySource(source);
|
|
503
|
+
|
|
504
|
+
assert.equal(result.valid, false, 'config with multiple missing fields must fail');
|
|
505
|
+
assert.ok(result.errors.length >= 2, 'must accumulate at least two errors');
|
|
506
|
+
assert.ok(
|
|
507
|
+
result.errors.some((e) => /name/i.test(e)),
|
|
508
|
+
'errors must include a name error'
|
|
509
|
+
);
|
|
510
|
+
assert.ok(
|
|
511
|
+
result.errors.some((e) => /repositoryRef/i.test(e)),
|
|
512
|
+
'errors must include a repositoryRef error'
|
|
513
|
+
);
|
|
514
|
+
});
|