@a5c-ai/krate 5.0.1-staging.f672fe79b
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 +29 -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 +2407 -0
- package/dist/krate-lifecycle.json +201 -0
- package/dist/krate-runtime-snapshot.json +2955 -0
- package/dist/krate-summary.json +687 -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/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/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/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 +207 -0
- package/src/agent-approval-controller.js +123 -0
- package/src/agent-context-bundles.js +242 -0
- package/src/agent-dispatch-controller.js +86 -0
- package/src/agent-mux-client.js +280 -0
- package/src/agent-permission-review.js +162 -0
- package/src/agent-stack-controller.js +296 -0
- package/src/agent-trigger-controller.js +108 -0
- package/src/api-controller.js +206 -0
- package/src/argocd-gitops.js +43 -0
- package/src/auth.js +265 -0
- package/src/component-catalog.js +41 -0
- package/src/control-plane.js +136 -0
- package/src/controller-client.js +38 -0
- package/src/controller-ui.js +538 -0
- package/src/data-plane.js +178 -0
- package/src/gitea-backend.js +95 -0
- package/src/handoff.js +98 -0
- package/src/hooks-events.js +63 -0
- package/src/http-server.js +151 -0
- package/src/identity-policy.js +86 -0
- package/src/index.js +30 -0
- package/src/kubernetes-controller.js +812 -0
- package/src/kubernetes-resource-gateway.js +48 -0
- package/src/operations.js +112 -0
- package/src/resource-model.js +203 -0
- package/src/runners-ci.js +48 -0
- package/src/runtime.js +196 -0
- package/src/web-ui.js +40 -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 +176 -0
- package/tests/agent-mux-client.test.js +204 -0
- package/tests/agent-permission-review.test.js +209 -0
- package/tests/agent-resources.test.js +212 -0
- package/tests/agent-stack-controller.test.js +221 -0
- package/tests/agent-trigger-controller.test.js +211 -0
- package/tests/deployment.test.js +395 -0
- package/tests/e2e/lifecycle.test.js +117 -0
- package/tests/krate.test.js +727 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { clone, matchLabels, resourceKey, storageClassForKind, toKubernetesList, validateResource } from './resource-model.js';
|
|
2
|
+
import { defaultAuthorizer, evaluateAdmission } from './identity-policy.js';
|
|
3
|
+
|
|
4
|
+
export const STORAGE_BOUNDARY_DESCRIPTIONS = { etcd: 'Kubernetes etcd CRD config', postgres: 'Aggregated API Postgres records' };
|
|
5
|
+
|
|
6
|
+
export class ControlPlane {
|
|
7
|
+
constructor({ authorizer = defaultAuthorizer(), admissionPolicies = [] } = {}) {
|
|
8
|
+
this.authorizer = authorizer;
|
|
9
|
+
this.admissionPolicies = admissionPolicies;
|
|
10
|
+
this.stores = { etcd: new Map(), postgres: new Map() };
|
|
11
|
+
this.auditLog = [];
|
|
12
|
+
this.events = [];
|
|
13
|
+
this.watchers = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addAdmissionPolicy(policy) { this.admissionPolicies.push(policy); }
|
|
17
|
+
create(resource, user) { return this.#mutate('create', resource, user); }
|
|
18
|
+
update(resource, user) { return this.#mutate('update', resource, user); }
|
|
19
|
+
|
|
20
|
+
patchStatus(kind, namespace, name, statusPatch, user) {
|
|
21
|
+
const existing = this.get(kind, namespace, name);
|
|
22
|
+
if (!existing) throw new Error(`${kind}/${namespace}/${name} not found`);
|
|
23
|
+
const next = clone(existing);
|
|
24
|
+
next.status = { ...next.status, ...clone(statusPatch) };
|
|
25
|
+
return this.#mutate('update', next, user, { statusOnly: true });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get(kind, namespace = 'default', name) {
|
|
29
|
+
const storage = storageClassForKind(kind);
|
|
30
|
+
return clone(this.stores[storage].get(`${kind}/${namespace}/${name}`));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
list(kind, { namespace, labels } = {}) {
|
|
34
|
+
const storage = storageClassForKind(kind);
|
|
35
|
+
const items = [...this.stores[storage].values()]
|
|
36
|
+
.filter((resource) => resource.kind === kind)
|
|
37
|
+
.filter((resource) => !namespace || resource.metadata.namespace === namespace)
|
|
38
|
+
.filter((resource) => !labels || matchLabels(resource, labels))
|
|
39
|
+
.map(clone);
|
|
40
|
+
return toKubernetesList(kind, items);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
watch(kind, handler) {
|
|
44
|
+
if (!this.watchers.has(kind)) this.watchers.set(kind, new Set());
|
|
45
|
+
this.watchers.get(kind).add(handler);
|
|
46
|
+
return () => this.watchers.get(kind)?.delete(handler);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
storageReport() {
|
|
50
|
+
return {
|
|
51
|
+
etcd: [...this.stores.etcd.values()].map((resource) => resource.kind),
|
|
52
|
+
postgres: [...this.stores.postgres.values()].map((resource) => resource.kind)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exportSnapshot() {
|
|
57
|
+
return {
|
|
58
|
+
apiVersion: 'krate.a5c.ai/v1alpha1',
|
|
59
|
+
kind: 'ControlPlaneSnapshot',
|
|
60
|
+
stores: {
|
|
61
|
+
etcd: [...this.stores.etcd.values()].map(clone),
|
|
62
|
+
postgres: [...this.stores.postgres.values()].map(clone)
|
|
63
|
+
},
|
|
64
|
+
auditLog: clone(this.auditLog),
|
|
65
|
+
events: clone(this.events)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
importSnapshot(snapshot) {
|
|
70
|
+
if (!snapshot || typeof snapshot !== 'object') throw new Error('snapshot must be an object');
|
|
71
|
+
const stores = snapshot.stores || {};
|
|
72
|
+
const nextStores = { etcd: new Map(), postgres: new Map() };
|
|
73
|
+
for (const storage of ['etcd', 'postgres']) {
|
|
74
|
+
for (const resource of stores[storage] || []) {
|
|
75
|
+
const valid = validateResource(clone(resource));
|
|
76
|
+
const expectedStorage = storageClassForKind(valid.kind);
|
|
77
|
+
if (expectedStorage !== storage) throw new Error(`${valid.kind} belongs in ${expectedStorage}, not ${storage}`);
|
|
78
|
+
valid.status.storage = storage;
|
|
79
|
+
nextStores[storage].set(`${valid.kind}/${valid.metadata.namespace}/${valid.metadata.name}`, clone(valid));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
this.stores = nextStores;
|
|
83
|
+
this.auditLog = clone(snapshot.auditLog || []);
|
|
84
|
+
this.events = clone(snapshot.events || []);
|
|
85
|
+
this.#emit({ type: 'snapshot.imported', storage: 'control-plane', resource: createSnapshotResource(this.exportSnapshot()), audit: null });
|
|
86
|
+
return this.exportSnapshot();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#mutate(operation, resource, user, options = {}) {
|
|
90
|
+
const candidate = validateResource(clone(resource));
|
|
91
|
+
const namespace = candidate.metadata.namespace;
|
|
92
|
+
const verb = options.statusOnly ? 'update' : operation;
|
|
93
|
+
if (!this.authorizer.can(user, verb, candidate.kind, namespace)) {
|
|
94
|
+
throw new Error(`RBAC denied ${user?.name || 'anonymous'} ${verb} ${candidate.kind}`);
|
|
95
|
+
}
|
|
96
|
+
const admission = evaluateAdmission(this.admissionPolicies, { operation, resource: candidate, user, options });
|
|
97
|
+
const auditEntry = {
|
|
98
|
+
at: new Date().toISOString(),
|
|
99
|
+
operation,
|
|
100
|
+
user: user?.name || 'anonymous',
|
|
101
|
+
groups: user?.groups || [],
|
|
102
|
+
resource: resourceKey(candidate),
|
|
103
|
+
warnings: admission.warnings,
|
|
104
|
+
allowed: admission.allowed
|
|
105
|
+
};
|
|
106
|
+
this.auditLog.push(auditEntry);
|
|
107
|
+
if (!admission.allowed) {
|
|
108
|
+
const messages = admission.violations.map((violation) => violation.message).join('; ');
|
|
109
|
+
throw new Error(`Admission denied ${candidate.kind}: ${messages}`);
|
|
110
|
+
}
|
|
111
|
+
const storage = storageClassForKind(candidate.kind);
|
|
112
|
+
const key = `${candidate.kind}/${namespace}/${candidate.metadata.name}`;
|
|
113
|
+
candidate.metadata.resourceVersion = String((Number(this.stores[storage].get(key)?.metadata?.resourceVersion || 0) || 0) + 1);
|
|
114
|
+
candidate.status.storage = storage;
|
|
115
|
+
this.stores[storage].set(key, clone(candidate));
|
|
116
|
+
this.#emit({ type: operation, storage, resource: candidate, audit: auditEntry });
|
|
117
|
+
return clone(candidate);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
#emit(event) {
|
|
121
|
+
const publicEvent = { ...event, resource: clone(event.resource) };
|
|
122
|
+
this.events.push(publicEvent);
|
|
123
|
+
for (const handler of this.watchers.get(event.resource.kind) || []) handler(publicEvent);
|
|
124
|
+
for (const handler of this.watchers.get('*') || []) handler(publicEvent);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function createSnapshotResource(snapshot) {
|
|
129
|
+
return {
|
|
130
|
+
apiVersion: 'krate.a5c.ai/v1alpha1',
|
|
131
|
+
kind: 'ControlPlaneSnapshot',
|
|
132
|
+
metadata: { namespace: 'default', name: 'latest', labels: {}, annotations: {}, resourceVersion: '1' },
|
|
133
|
+
spec: { resourceCounts: Object.fromEntries(Object.entries(snapshot.stores).map(([storage, resources]) => [storage, resources.length])) },
|
|
134
|
+
status: { storage: 'control-plane', phase: 'Imported' }
|
|
135
|
+
};
|
|
136
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createControllerUiModel } from './controller-ui.js';
|
|
2
|
+
import { createKrateApiController } from './api-controller.js';
|
|
3
|
+
import { createKubernetesResourceGateway } from './kubernetes-resource-gateway.js';
|
|
4
|
+
|
|
5
|
+
export async function fetchControllerUiModel({ controllerUrl = process.env.KRATE_CONTROLLER_URL, fetchImpl = globalThis.fetch, controller = createKrateApiController({ resourceGateway: createKubernetesResourceGateway() }), organization = process.env.KRATE_ORG || null } = {}) {
|
|
6
|
+
if (controllerUrl) {
|
|
7
|
+
try {
|
|
8
|
+
const target = new URL('/api/controller', controllerUrl);
|
|
9
|
+
if (organization) target.searchParams.set('org', organization);
|
|
10
|
+
const response = await fetchImpl(target, { cache: 'no-store' });
|
|
11
|
+
if (!response.ok) throw new Error(`controller API ${response.status}`);
|
|
12
|
+
return response.json();
|
|
13
|
+
} catch (error) {
|
|
14
|
+
return fallbackControllerModel(controller, error, organization);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return fallbackControllerModel(controller, null, organization);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function fallbackControllerModel(controller, connectionError = null, organization = null) {
|
|
21
|
+
try {
|
|
22
|
+
const model = createControllerUiModel(await controller.snapshot(), { organization });
|
|
23
|
+
if (connectionError) model.controller.connection.errors = [connectionError.message, ...(model.controller.connection.errors || [])];
|
|
24
|
+
return model;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return createControllerUiModel({
|
|
27
|
+
source: 'kubernetes',
|
|
28
|
+
namespace: process.env.KRATE_NAMESPACE || 'krate-system',
|
|
29
|
+
kubectl: { available: false, context: null, errors: [connectionError?.message, error.message].filter(Boolean) },
|
|
30
|
+
resources: {},
|
|
31
|
+
crds: [],
|
|
32
|
+
events: [],
|
|
33
|
+
permissions: [],
|
|
34
|
+
storage: {},
|
|
35
|
+
commands: []
|
|
36
|
+
}, { organization });
|
|
37
|
+
}
|
|
38
|
+
}
|