@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,78 @@
|
|
|
1
|
+
# User Stories
|
|
2
|
+
|
|
3
|
+
## Developer stories
|
|
4
|
+
|
|
5
|
+
### Open and review a PR
|
|
6
|
+
|
|
7
|
+
As a developer, I want to review a PR in a three-pane view with file tree, diff, conversation, inline comments, suggested edits, and CI status so that I can complete reviews quickly.
|
|
8
|
+
|
|
9
|
+
Acceptance criteria:
|
|
10
|
+
|
|
11
|
+
- Given I open a PR, when the page loads, then I see changed files, diff, discussion, reviewers, merge state, and related pipeline runs.
|
|
12
|
+
- Given I use keyboard shortcuts, when I press navigation keys, then I can move between files and comments without leaving the keyboard.
|
|
13
|
+
- Given I add a suggested edit, when I submit it, then the UI exposes the equivalent resource/YAML mutation.
|
|
14
|
+
|
|
15
|
+
### Debug a failing run
|
|
16
|
+
|
|
17
|
+
As a developer, I want a live run view with step navigation, log streaming, failure copy, similar-run search, and rerun controls so that I can diagnose failures without switching tools.
|
|
18
|
+
|
|
19
|
+
Acceptance criteria:
|
|
20
|
+
|
|
21
|
+
- Given a job is running, when logs are emitted, then the UI streams them through SSE without polling.
|
|
22
|
+
- Given a step fails, when I click find similar runs, then Krate queries pipelines by failure signature labels.
|
|
23
|
+
- Given I rerun from a step, when I submit, then Krate creates a new `Pipeline` with `resumeFrom`.
|
|
24
|
+
|
|
25
|
+
## Platform engineer stories
|
|
26
|
+
|
|
27
|
+
### Configure a runner pool
|
|
28
|
+
|
|
29
|
+
As a platform engineer, I want a split form/YAML runner pool editor so that pool configuration is easy to edit and still GitOps-auditable.
|
|
30
|
+
|
|
31
|
+
Acceptance criteria:
|
|
32
|
+
|
|
33
|
+
- Given I edit image, resources, node selector, warm replicas, max replicas, trust tier, and cache backend, when fields change, then YAML updates live.
|
|
34
|
+
- Given I save, when the operation succeeds, then the same manifest can be copied as `kubectl apply`.
|
|
35
|
+
- Given I click save to repo, when configured, then Krate opens a PR against the platform config repo.
|
|
36
|
+
|
|
37
|
+
### Roll out PR policy safely
|
|
38
|
+
|
|
39
|
+
As a platform engineer, I want policy templates, CEL/raw modes, audit preview, and enforcement controls so that I can govern PRs without breaking teams unexpectedly.
|
|
40
|
+
|
|
41
|
+
Acceptance criteria:
|
|
42
|
+
|
|
43
|
+
- Given I select a policy template, when I preview it, then existing PRs that would violate the policy are listed.
|
|
44
|
+
- Given the policy is in audit mode, when a violating PR is created, then it is recorded but not blocked.
|
|
45
|
+
- Given I switch to enforce mode, when a violating PR is created, then admission blocks it with an actionable message.
|
|
46
|
+
|
|
47
|
+
## Repo admin stories
|
|
48
|
+
|
|
49
|
+
### Add and verify a webhook
|
|
50
|
+
|
|
51
|
+
As a repo admin, I want to create a webhook, send a test delivery, inspect failures, and replay deliveries so integrations are operationally transparent.
|
|
52
|
+
|
|
53
|
+
Acceptance criteria:
|
|
54
|
+
|
|
55
|
+
- Given I create a subscription, when I send a test delivery, then a `WebhookDelivery` resource appears within seconds.
|
|
56
|
+
- Given delivery fails, when I open the log, then I see request headers, body, response, latency, retries, and error details.
|
|
57
|
+
- Given I click replay, when secrets are current, then Krate re-fires the event and records a new delivery attempt.
|
|
58
|
+
|
|
59
|
+
## Team lead stories
|
|
60
|
+
|
|
61
|
+
### Cross-repo triage
|
|
62
|
+
|
|
63
|
+
As a team lead, I want inbox filters and saved views stored as resources so that triage workflows can be versioned and shared.
|
|
64
|
+
|
|
65
|
+
Acceptance criteria:
|
|
66
|
+
|
|
67
|
+
- Given I create a filter for priority issues and PRs, when I save it, then Krate stores a `Selector` or `View` resource.
|
|
68
|
+
- Given another user applies the resource, when they open the inbox, then they see the same triage view.
|
|
69
|
+
- Given the view is exported, when committed to Git, then it can be reviewed and applied like any other config.
|
|
70
|
+
|
|
71
|
+
## Excellent-flow coverage
|
|
72
|
+
|
|
73
|
+
- Open and review a PR.
|
|
74
|
+
- Debug a failing run.
|
|
75
|
+
- Configure a runner pool.
|
|
76
|
+
- Add a webhook and verify it works.
|
|
77
|
+
- Write a PR policy with audit-to-enforce rollout.
|
|
78
|
+
- Cross-repo triage with saved filters.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
2
|
+
kind: Organization
|
|
3
|
+
metadata:
|
|
4
|
+
name: krate
|
|
5
|
+
namespace: krate-system
|
|
6
|
+
spec:
|
|
7
|
+
displayName: Krate
|
|
8
|
+
description: Krate-managed default organization
|
|
9
|
+
owners:
|
|
10
|
+
- platform
|
|
11
|
+
slug: krate
|
|
12
|
+
namespaceName: krate-org-krate
|
|
13
|
+
---
|
|
14
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
15
|
+
kind: SSHKey
|
|
16
|
+
metadata:
|
|
17
|
+
name: platform-deploy
|
|
18
|
+
namespace: krate-org-krate
|
|
19
|
+
labels:
|
|
20
|
+
krate.a5c.ai/org: krate
|
|
21
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
22
|
+
spec:
|
|
23
|
+
scope: deploy
|
|
24
|
+
owner: krate
|
|
25
|
+
repository: krate-demo
|
|
26
|
+
title: platform deploy key
|
|
27
|
+
key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKrateDemoKey platform@example.test
|
|
28
|
+
readOnly: true
|
|
29
|
+
organizationRef: krate
|
|
30
|
+
---
|
|
31
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
32
|
+
kind: RepositoryPermission
|
|
33
|
+
metadata:
|
|
34
|
+
name: krate-demo-maintainers
|
|
35
|
+
namespace: krate-org-krate
|
|
36
|
+
labels:
|
|
37
|
+
krate.a5c.ai/org: krate
|
|
38
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
39
|
+
spec:
|
|
40
|
+
repository: krate-demo
|
|
41
|
+
subjectKind: team
|
|
42
|
+
subject: maintainers
|
|
43
|
+
permission: admin
|
|
44
|
+
organizationRef: krate
|
|
45
|
+
---
|
|
46
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
47
|
+
kind: Repository
|
|
48
|
+
metadata:
|
|
49
|
+
name: krate-demo
|
|
50
|
+
namespace: krate-org-krate
|
|
51
|
+
labels:
|
|
52
|
+
krate.a5c.ai/org: krate
|
|
53
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
54
|
+
spec:
|
|
55
|
+
visibility: internal
|
|
56
|
+
defaultBranch: main
|
|
57
|
+
organizationRef: krate
|
|
58
|
+
---
|
|
59
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
60
|
+
kind: BranchProtection
|
|
61
|
+
metadata:
|
|
62
|
+
name: main-protection
|
|
63
|
+
namespace: krate-org-krate
|
|
64
|
+
labels:
|
|
65
|
+
krate.a5c.ai/org: krate
|
|
66
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
67
|
+
spec:
|
|
68
|
+
refs:
|
|
69
|
+
- refs/heads/main
|
|
70
|
+
requirePullRequest: true
|
|
71
|
+
organizationRef: krate
|
|
72
|
+
---
|
|
73
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
74
|
+
kind: RefPolicy
|
|
75
|
+
metadata:
|
|
76
|
+
name: deny-internal-refs
|
|
77
|
+
namespace: krate-org-krate
|
|
78
|
+
labels:
|
|
79
|
+
krate.a5c.ai/org: krate
|
|
80
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
81
|
+
spec:
|
|
82
|
+
deny:
|
|
83
|
+
- refs/internal/
|
|
84
|
+
organizationRef: krate
|
|
85
|
+
---
|
|
86
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
87
|
+
kind: RunnerPool
|
|
88
|
+
metadata:
|
|
89
|
+
name: trusted-linux
|
|
90
|
+
namespace: krate-org-krate
|
|
91
|
+
labels:
|
|
92
|
+
krate.a5c.ai/org: krate
|
|
93
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
94
|
+
spec:
|
|
95
|
+
warmReplicas: 1
|
|
96
|
+
maxReplicas: 4
|
|
97
|
+
organizationRef: krate
|
|
98
|
+
---
|
|
99
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
100
|
+
kind: WebhookSubscription
|
|
101
|
+
metadata:
|
|
102
|
+
name: chatops
|
|
103
|
+
namespace: krate-org-krate
|
|
104
|
+
labels:
|
|
105
|
+
krate.a5c.ai/org: krate
|
|
106
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
107
|
+
spec:
|
|
108
|
+
url: https://hooks.example.test/krate
|
|
109
|
+
events:
|
|
110
|
+
- pullrequest.created
|
|
111
|
+
organizationRef: krate
|
|
112
|
+
---
|
|
113
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
114
|
+
kind: Pipeline
|
|
115
|
+
metadata:
|
|
116
|
+
name: demo-pr-checks
|
|
117
|
+
labels:
|
|
118
|
+
repository: krate-demo
|
|
119
|
+
workflow: pull-request
|
|
120
|
+
krate.a5c.ai/org: krate
|
|
121
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
122
|
+
namespace: krate-org-krate
|
|
123
|
+
spec:
|
|
124
|
+
repository: krate-demo
|
|
125
|
+
ref: refs/pull/1/head
|
|
126
|
+
runnerPool: trusted-linux
|
|
127
|
+
trustTier: trusted
|
|
128
|
+
steps:
|
|
129
|
+
- checkout
|
|
130
|
+
- test
|
|
131
|
+
- publish
|
|
132
|
+
organizationRef: krate
|
|
133
|
+
---
|
|
134
|
+
apiVersion: argoproj.io/v1alpha1
|
|
135
|
+
kind: Application
|
|
136
|
+
metadata:
|
|
137
|
+
name: krate-demo
|
|
138
|
+
namespace: argocd
|
|
139
|
+
spec:
|
|
140
|
+
project: default
|
|
141
|
+
source:
|
|
142
|
+
repoURL: https://gitea-http.krate-system.svc.cluster.local/krate/platform-config.git
|
|
143
|
+
targetRevision: main
|
|
144
|
+
path: charts/krate
|
|
145
|
+
destination:
|
|
146
|
+
server: https://kubernetes.default.svc
|
|
147
|
+
namespace: krate-system
|
|
148
|
+
syncPolicy:
|
|
149
|
+
automated:
|
|
150
|
+
prune: true
|
|
151
|
+
selfHeal: true
|
|
152
|
+
syncOptions:
|
|
153
|
+
- CreateNamespace=true
|
|
154
|
+
---
|
|
155
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
156
|
+
kind: Issue
|
|
157
|
+
metadata:
|
|
158
|
+
name: issue-1
|
|
159
|
+
namespace: krate-org-krate
|
|
160
|
+
labels:
|
|
161
|
+
krate.a5c.ai/org: krate
|
|
162
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
163
|
+
spec:
|
|
164
|
+
repository: krate-demo
|
|
165
|
+
title: Wire Krate-managed permissions
|
|
166
|
+
labels:
|
|
167
|
+
- forge
|
|
168
|
+
- access
|
|
169
|
+
organizationRef: krate
|
|
170
|
+
status:
|
|
171
|
+
phase: triage
|
|
172
|
+
---
|
|
173
|
+
apiVersion: krate.a5c.ai/v1alpha1
|
|
174
|
+
kind: PullRequest
|
|
175
|
+
metadata:
|
|
176
|
+
name: pr-1
|
|
177
|
+
namespace: krate-org-krate
|
|
178
|
+
labels:
|
|
179
|
+
krate.a5c.ai/org: krate
|
|
180
|
+
krate.a5c.ai/namespace: krate-org-krate
|
|
181
|
+
spec:
|
|
182
|
+
repository: krate-demo
|
|
183
|
+
title: Improve forge UI
|
|
184
|
+
head: feature/forge-ui
|
|
185
|
+
base: main
|
|
186
|
+
organizationRef: krate
|
|
187
|
+
status:
|
|
188
|
+
phase: Open
|
|
189
|
+
changedFiles:
|
|
190
|
+
- apps/web/app/ui-shell.jsx
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
apiVersion: core.oam.dev/v1beta1
|
|
2
|
+
kind: Application
|
|
3
|
+
metadata:
|
|
4
|
+
name: krate-demo-app
|
|
5
|
+
namespace: krate-system
|
|
6
|
+
labels:
|
|
7
|
+
krate.a5c.ai/repository: krate-demo
|
|
8
|
+
spec:
|
|
9
|
+
components:
|
|
10
|
+
- name: krate-demo
|
|
11
|
+
type: webservice
|
|
12
|
+
properties:
|
|
13
|
+
image: krate/mvp-model:0.1.0
|
|
14
|
+
traits:
|
|
15
|
+
- type: scaler
|
|
16
|
+
properties:
|
|
17
|
+
replicas: 1
|
|
18
|
+
scopes:
|
|
19
|
+
healthscopes.core.oam.dev: krate-demo-health
|
|
20
|
+
workflow:
|
|
21
|
+
steps:
|
|
22
|
+
- name: deploy
|
|
23
|
+
type: deploy
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
apiVersion: kyverno.io/v1
|
|
2
|
+
kind: ClusterPolicy
|
|
3
|
+
metadata:
|
|
4
|
+
name: krate-pullrequest-title-required
|
|
5
|
+
spec:
|
|
6
|
+
validationFailureAction: Enforce
|
|
7
|
+
rules:
|
|
8
|
+
- name: require-descriptive-pr-title
|
|
9
|
+
match:
|
|
10
|
+
any:
|
|
11
|
+
- resources:
|
|
12
|
+
kinds:
|
|
13
|
+
- PullRequest.krate.a5c.ai/v1alpha1
|
|
14
|
+
validate:
|
|
15
|
+
message: PullRequest spec.title must be descriptive.
|
|
16
|
+
pattern:
|
|
17
|
+
spec:
|
|
18
|
+
title: "?*"
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@a5c-ai/krate",
|
|
3
|
+
"version": "5.0.1-staging.f672fe79b",
|
|
4
|
+
"description": "a5c.ai Krate: Kubernetes-native forge runtime with Argo CD GitOps and Gitea-backed Git hosting.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"krate-demo": "./bin/krate-demo.mjs",
|
|
12
|
+
"krate-server": "./bin/krate-server.mjs"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "node scripts/build.mjs",
|
|
16
|
+
"test": "node --test tests/*.test.js",
|
|
17
|
+
"validate:docs": "node scripts/validate-doc-coverage.mjs",
|
|
18
|
+
"smoke": "node scripts/smoke.mjs",
|
|
19
|
+
"check": "npm run build && npm run validate:docs && npm test && npm run e2e && npm run package:check && npm run smoke",
|
|
20
|
+
"demo": "node bin/krate-demo.mjs",
|
|
21
|
+
"e2e": "node --test tests/e2e/*.test.js",
|
|
22
|
+
"package:check": "node scripts/validate-package.mjs",
|
|
23
|
+
"setup:minikube": "node scripts/setup-minikube.mjs",
|
|
24
|
+
"serve": "node bin/krate-server.mjs"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"kubernetes",
|
|
28
|
+
"forge",
|
|
29
|
+
"git",
|
|
30
|
+
"ci",
|
|
31
|
+
"rbac",
|
|
32
|
+
"webhooks"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {},
|
|
39
|
+
"author": "a5c.ai",
|
|
40
|
+
"homepage": "https://github.com/a5c-ai/babysitter/tree/main/packages/krate/core#readme",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/a5c-ai/babysitter.git",
|
|
44
|
+
"directory": "packages/krate/core"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/a5c-ai/babysitter/issues"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"bin",
|
|
54
|
+
"src",
|
|
55
|
+
"dist",
|
|
56
|
+
"scripts",
|
|
57
|
+
"docs",
|
|
58
|
+
"examples",
|
|
59
|
+
"tests",
|
|
60
|
+
"Dockerfile",
|
|
61
|
+
"README.md"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { createControllerUiModel, createKrateHandoffSummary, createKrateMvpDemo, createKrateRuntime } from '../src/index.js';
|
|
4
|
+
|
|
5
|
+
const packageInfo = JSON.parse(await readFile('package.json', 'utf8'));
|
|
6
|
+
const runtime = createKrateRuntime();
|
|
7
|
+
const controller = createControllerUiModel(runtime);
|
|
8
|
+
const snapshot = runtime.snapshot();
|
|
9
|
+
const demo = createKrateMvpDemo();
|
|
10
|
+
const lifecycle = demo.lifecycle;
|
|
11
|
+
const summary = createKrateHandoffSummary(demo, { packageInfo });
|
|
12
|
+
summary.controller = {
|
|
13
|
+
status: controller.status,
|
|
14
|
+
namespace: controller.namespace,
|
|
15
|
+
endpoints: controller.controller.endpoints,
|
|
16
|
+
metrics: controller.metrics,
|
|
17
|
+
operations: controller.operations
|
|
18
|
+
};
|
|
19
|
+
summary.runtime = {
|
|
20
|
+
resources: Object.fromEntries(Object.entries(snapshot.resources).map(([kind, resources]) => [kind, resources.length])),
|
|
21
|
+
events: snapshot.events.length,
|
|
22
|
+
auditEntries: snapshot.auditLog.length
|
|
23
|
+
};
|
|
24
|
+
await mkdir('dist', { recursive: true });
|
|
25
|
+
await writeFile('dist/krate-summary.json', JSON.stringify(summary, null, 2));
|
|
26
|
+
await writeFile('dist/krate-controller-ui.json', JSON.stringify(controller, null, 2));
|
|
27
|
+
await writeFile('dist/krate-runtime-snapshot.json', JSON.stringify(snapshot, null, 2));
|
|
28
|
+
await writeFile('dist/krate-lifecycle.json', JSON.stringify(lifecycle, null, 2));
|
|
29
|
+
console.log('build ok: dist/krate-summary.json dist/krate-controller-ui.json dist/krate-runtime-snapshot.json dist/krate-lifecycle.json');
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
|
|
4
|
+
export function parseArgs(argv = process.argv.slice(2)) {
|
|
5
|
+
const options = { apply: false, json: false, profile: 'krate', namespace: 'krate-system', release: 'krate', driver: 'docker', chart: '../charts' };
|
|
6
|
+
for (const arg of argv) {
|
|
7
|
+
if (arg === '--apply') options.apply = true;
|
|
8
|
+
else if (arg === '--dry-run') options.apply = false;
|
|
9
|
+
else if (arg === '--json') options.json = true;
|
|
10
|
+
else if (arg.startsWith('--profile=')) options.profile = arg.slice('--profile='.length);
|
|
11
|
+
else if (arg.startsWith('--namespace=')) options.namespace = arg.slice('--namespace='.length);
|
|
12
|
+
else if (arg.startsWith('--release=')) options.release = arg.slice('--release='.length);
|
|
13
|
+
else if (arg.startsWith('--driver=')) options.driver = arg.slice('--driver='.length);
|
|
14
|
+
else if (arg.startsWith('--chart=')) options.chart = arg.slice('--chart='.length);
|
|
15
|
+
else throw new Error(`Unknown option: ${arg}`);
|
|
16
|
+
}
|
|
17
|
+
return options;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function buildMinikubePlan(options = parseArgs([])) {
|
|
21
|
+
const { profile, namespace, release, driver, chart } = options;
|
|
22
|
+
return {
|
|
23
|
+
mode: options.apply ? 'apply' : 'dry-run',
|
|
24
|
+
requiredTools: ['minikube', 'kubectl', 'helm', 'node', 'npm'],
|
|
25
|
+
commands: [
|
|
26
|
+
['minikube', ['start', '-p', profile, '--driver', driver]],
|
|
27
|
+
['minikube', ['addons', 'enable', 'ingress', '-p', profile]],
|
|
28
|
+
['minikube', ['addons', 'enable', 'metrics-server', '-p', profile]],
|
|
29
|
+
['kubectl', ['config', 'use-context', profile]],
|
|
30
|
+
['kubectl', ['create', 'namespace', namespace, '--dry-run=client', '-o', 'yaml']],
|
|
31
|
+
['helm', ['lint', chart]],
|
|
32
|
+
['helm', ['upgrade', '--install', release, chart, '--namespace', namespace, '--create-namespace', '--set', 'demo.enabled=true']],
|
|
33
|
+
['kubectl', ['apply', '-n', namespace, '-f', 'examples/minikube-demo.yaml']],
|
|
34
|
+
['kubectl', ['wait', '--for=condition=Available', `deployment/${release}-krate-api`, '-n', namespace, '--timeout=120s']],
|
|
35
|
+
['node', ['scripts/smoke.mjs']]
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function commandToString([command, args]) {
|
|
41
|
+
return [command, ...args].join(' ');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function runCommand(command) {
|
|
45
|
+
const [bin, args] = command;
|
|
46
|
+
const result = spawnSync(bin, args, { stdio: 'inherit', shell: process.platform === 'win32' });
|
|
47
|
+
if (result.status !== 0) throw new Error(`Command failed: ${commandToString(command)}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const isMain = process.argv[1]?.replace(/\\/g, '/').endsWith('/scripts/setup-minikube.mjs');
|
|
51
|
+
if (isMain) {
|
|
52
|
+
try {
|
|
53
|
+
const options = parseArgs();
|
|
54
|
+
const plan = buildMinikubePlan(options);
|
|
55
|
+
if (options.json) console.log(JSON.stringify({ ...plan, commands: plan.commands.map(commandToString) }, null, 2));
|
|
56
|
+
else {
|
|
57
|
+
console.log(`Krate minikube setup (${plan.mode})`);
|
|
58
|
+
for (const command of plan.commands) console.log(`- ${commandToString(command)}`);
|
|
59
|
+
}
|
|
60
|
+
if (options.apply) for (const command of plan.commands) runCommand(command);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(error.message);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createKrateHttpServer, createKrateRuntime, runSmokeAssertions } from '../src/index.js';
|
|
2
|
+
|
|
3
|
+
const runtime = createKrateRuntime();
|
|
4
|
+
const server = createKrateHttpServer({ runtime });
|
|
5
|
+
const checks = [];
|
|
6
|
+
|
|
7
|
+
function record(name, passed, evidence = '') {
|
|
8
|
+
checks.push({ name, passed: Boolean(passed), evidence });
|
|
9
|
+
console.log(`${passed ? 'ok' : 'not ok'} - ${name}${evidence ? ` (${evidence})` : ''}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
await new Promise((resolve) => server.listen(0, resolve));
|
|
13
|
+
const base = `http://127.0.0.1:${server.address().port}`;
|
|
14
|
+
let model;
|
|
15
|
+
try {
|
|
16
|
+
const health = await fetch(`${base}/healthz`);
|
|
17
|
+
record('HTTP health endpoint is live', health.ok, '/healthz');
|
|
18
|
+
const modelResponse = await fetch(`${base}/api/controller`);
|
|
19
|
+
model = await modelResponse.json();
|
|
20
|
+
record('Controller API exposes Krate workspace model', modelResponse.ok && model.controller.mode === 'krate-workspace', '/api/controller');
|
|
21
|
+
record('Controller model reports truthful ready or degraded state', ['ready', 'degraded'].includes(model.status) && Number.isFinite(model.metrics.resources), `${model.status}; ${model.metrics.resources} resources`);
|
|
22
|
+
record('Controller model includes Krate management endpoints', model.controller.endpoints.some((endpoint) => endpoint.path === '/api/orgs/:org/resources') && model.controller.endpoints.some((endpoint) => endpoint.path === '/api/orgs/:org/repositories'), model.controller.endpoints.map((endpoint) => endpoint.path).join(', '));
|
|
23
|
+
record('Controller model includes publishing gates', model.operations.releaseGates.includes('npm pack --json') && model.operations.releaseGates.includes('docker build'), model.operations.releaseGates.join(', '));
|
|
24
|
+
const snapshotResponse = await fetch(`${base}/api/orgs/default/snapshot`);
|
|
25
|
+
const snapshot = await snapshotResponse.json();
|
|
26
|
+
record('Org snapshot endpoint exports durable runtime state', snapshotResponse.ok && snapshot.export?.controlPlane && snapshot.resources?.Repository?.length > 0, '/api/orgs/default/snapshot');
|
|
27
|
+
} finally {
|
|
28
|
+
await new Promise((resolve) => server.close(resolve));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const contractSmoke = runSmokeAssertions();
|
|
32
|
+
for (const [name, passed] of contractSmoke.assertions) record(name, passed, 'runtime contract compatibility');
|
|
33
|
+
if (!checks.every((check) => check.passed)) {
|
|
34
|
+
console.error(JSON.stringify({ status: 'failed', checks }, null, 2));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
console.log(JSON.stringify({ status: 'success', checks: checks.length, controllerStatus: model.status, resources: model.metrics.resources }, null, 2));
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
|
|
3
|
+
const requiredDocs = [
|
|
4
|
+
'README.md',
|
|
5
|
+
'docs/README.md',
|
|
6
|
+
'docs/product-requirements.md',
|
|
7
|
+
'docs/system-requirements.md',
|
|
8
|
+
'docs/architecture-spec.md',
|
|
9
|
+
'docs/user-stories.md',
|
|
10
|
+
'docs/roadmap-mvp.md',
|
|
11
|
+
'docs/install.md',
|
|
12
|
+
'docs/local-minikube.md',
|
|
13
|
+
'docs/components/control-plane.md',
|
|
14
|
+
'docs/components/data-plane.md',
|
|
15
|
+
'docs/components/identity-rbac-policy.md',
|
|
16
|
+
'docs/components/runners-ci.md',
|
|
17
|
+
'docs/components/hooks-events.md',
|
|
18
|
+
'docs/components/web-ui.md',
|
|
19
|
+
'docs/components/operations-publishing.md',
|
|
20
|
+
'docs/components/kubevela-oam.md'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const requiredOntology = [
|
|
24
|
+
'docs/ontology/README.md',
|
|
25
|
+
'docs/ontology/world.md',
|
|
26
|
+
'docs/ontology/problem-space.md',
|
|
27
|
+
'docs/ontology/solution-space.md',
|
|
28
|
+
'docs/ontology/bounded-contexts.md',
|
|
29
|
+
'docs/ontology/resource-taxonomy.md',
|
|
30
|
+
'docs/ontology/resource-contracts.md',
|
|
31
|
+
'docs/ontology/personas-and-actors.md',
|
|
32
|
+
'docs/ontology/workflows.md',
|
|
33
|
+
'docs/ontology/policies-and-invariants.md',
|
|
34
|
+
'docs/ontology/storage-and-data-boundaries.md',
|
|
35
|
+
'docs/ontology/events-and-hooks.md',
|
|
36
|
+
'docs/ontology/runners-and-ci.md',
|
|
37
|
+
'docs/ontology/web-ui-excellent-flows.md',
|
|
38
|
+
'docs/ontology/operations-and-release.md',
|
|
39
|
+
'docs/ontology/validation-matrix.md',
|
|
40
|
+
'docs/ontology/oam-kubevela.md'
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const implementationFiles = [
|
|
44
|
+
'src/resource-model.js',
|
|
45
|
+
'src/control-plane.js',
|
|
46
|
+
'src/data-plane.js',
|
|
47
|
+
'src/identity-policy.js',
|
|
48
|
+
'src/runners-ci.js',
|
|
49
|
+
'src/hooks-events.js',
|
|
50
|
+
'src/web-ui.js',
|
|
51
|
+
'src/operations.js',
|
|
52
|
+
'tests/krate.test.js'
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
async function readRequired(file) {
|
|
56
|
+
try {
|
|
57
|
+
return await readFile(file, 'utf8');
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new Error(`${file} missing or unreadable: ${error.message}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const docsText = (await Promise.all(requiredDocs.map(readRequired))).join('\n');
|
|
64
|
+
const ontologyByFile = Object.fromEntries(await Promise.all(requiredOntology.map(async (file) => [file, await readRequired(file)])));
|
|
65
|
+
const ontologyText = Object.values(ontologyByFile).join('\n');
|
|
66
|
+
const sourceByFile = Object.fromEntries(await Promise.all(implementationFiles.map(async (file) => [file, await readRequired(file)])));
|
|
67
|
+
const allRequirementsText = `${docsText}\n${ontologyText}`;
|
|
68
|
+
|
|
69
|
+
const requiredTerms = [
|
|
70
|
+
'Repository', 'PullRequest', 'Issue', 'Review', 'Pipeline', 'Job', 'RunnerPool',
|
|
71
|
+
'WebhookSubscription', 'WebhookDelivery', 'RefPolicy', 'BranchProtection', 'View', 'Selector',
|
|
72
|
+
'RBAC', 'OIDC', 'Postgres', 'etcd', 'receive-pack', 'GitOps', 'backup', 'restore',
|
|
73
|
+
'APIService', 'fork', 'admission', 'webhook', 'object storage', 'search', 'release gates', 'KubeVela', 'OAM', 'Application', 'Component', 'Trait', 'Workflow Step'
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const sourceTerms = [
|
|
77
|
+
['RESOURCE_DEFINITIONS', 'src/resource-model.js'],
|
|
78
|
+
['resourceSchemaForKind', 'src/resource-model.js'],
|
|
79
|
+
['watch', 'src/control-plane.js'],
|
|
80
|
+
['auditLog', 'src/control-plane.js'],
|
|
81
|
+
['recordObject', 'src/data-plane.js'],
|
|
82
|
+
['enqueueSearchIndex', 'src/data-plane.js'],
|
|
83
|
+
['serviceAccountForJob', 'src/identity-policy.js'],
|
|
84
|
+
['rerunFromStep', 'src/runners-ci.js'],
|
|
85
|
+
['inspect', 'src/hooks-events.js'],
|
|
86
|
+
['createWebhookInspector', 'src/web-ui.js'],
|
|
87
|
+
['observabilityModel', 'src/operations.js'],
|
|
88
|
+
['releaseGates', 'src/operations.js']
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const workflowText = await readRequired('.github/workflows/publish.yml');
|
|
92
|
+
const releaseSurfaceTerms = [
|
|
93
|
+
['Dockerfile', docsText],
|
|
94
|
+
['controller image', docsText],
|
|
95
|
+
['GitHub publishing', docsText],
|
|
96
|
+
['GHCR', docsText],
|
|
97
|
+
['Helm chart', docsText],
|
|
98
|
+
['Live-cluster conformance', docsText],
|
|
99
|
+
['docker/build-push-action', workflowText],
|
|
100
|
+
['helm push', workflowText],
|
|
101
|
+
['npm pack', workflowText]
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const staleReleaseBoundaryPhrases = [
|
|
105
|
+
'does not claim to ship production controller images yet',
|
|
106
|
+
'does not yet ship production controller images',
|
|
107
|
+
'Real controller images, registry publication, and live-cluster conformance remain follow-up release work',
|
|
108
|
+
'Production controller images, registry publication, and live-cluster conformance still remain tracked follow-ups'
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
const ontologyExpectations = [
|
|
112
|
+
['docs/ontology/resource-taxonomy.md', ['CRD-backed', 'Aggregated', 'Repository', 'WebhookDelivery']],
|
|
113
|
+
['docs/ontology/resource-contracts.md', ['metadata.name', 'resourceVersion', 'RunnerPool', 'WebhookDelivery']],
|
|
114
|
+
['docs/ontology/policies-and-invariants.md', ['RBAC', 'Admission', 'Fork PR', 'BranchProtection']],
|
|
115
|
+
['docs/ontology/storage-and-data-boundaries.md', ['etcd', 'Postgres', 'Gitea', 'Object storage', 'Search']],
|
|
116
|
+
['docs/ontology/validation-matrix.md',
|
|
117
|
+
'docs/ontology/oam-kubevela.md', ['npm run check', 'docs and ontology coverage']]
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
const missing = [];
|
|
121
|
+
for (const term of requiredTerms) {
|
|
122
|
+
if (!allRequirementsText.includes(term)) missing.push(`requirements/ontology missing term: ${term}`);
|
|
123
|
+
}
|
|
124
|
+
for (const [term, file] of sourceTerms) {
|
|
125
|
+
if (!sourceByFile[file]?.includes(term)) missing.push(`${file} missing implementation term: ${term}`);
|
|
126
|
+
}
|
|
127
|
+
for (const [term, text] of releaseSurfaceTerms) {
|
|
128
|
+
if (!text.includes(term)) missing.push(`release surface missing term: ${term}`);
|
|
129
|
+
}
|
|
130
|
+
for (const phrase of staleReleaseBoundaryPhrases) {
|
|
131
|
+
if (allRequirementsText.includes(phrase)) missing.push(`stale release boundary phrase still present: ${phrase}`);
|
|
132
|
+
}
|
|
133
|
+
for (const [file, terms] of ontologyExpectations) {
|
|
134
|
+
for (const term of terms) {
|
|
135
|
+
if (!ontologyByFile[file]?.includes(term)) missing.push(`${file} missing ontology term: ${term}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (missing.length) {
|
|
140
|
+
console.error(JSON.stringify({ status: 'failed', missing }, null, 2));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
console.log(JSON.stringify({
|
|
145
|
+
status: 'success',
|
|
146
|
+
checkedDocs: requiredDocs.length,
|
|
147
|
+
checkedOntologyFiles: requiredOntology.length,
|
|
148
|
+
checkedImplementationFiles: implementationFiles.length,
|
|
149
|
+
requiredTerms: requiredTerms.length,
|
|
150
|
+
sourceTerms: sourceTerms.length,
|
|
151
|
+
releaseSurfaceTerms: releaseSurfaceTerms.length
|
|
152
|
+
}, null, 2));
|