6 Commits
Author SHA1 Message Date
Gitea Actions 6f67b8012f Release 0.1.4 [auto-version-bump] 2026-10-20 11:38:55 +02:00
Ein Anderssono 300bc3c61c Version the rule schema with releases
Build and publish rule engine / release (push) Failing after 2m32s
2026-10-20 11:38:41 +02:00
Gitea Actions 7e92eb651c Release 0.1.3 [auto-version-bump] 2026-10-20 11:35:28 +02:00
Ein Anderssono b9f832858a Scope rule engine rollout permissions
Build and publish rule engine / release (push) Failing after 11s
2026-10-20 11:35:18 +02:00
Gitea Actions b4349b49c4 Release 0.1.2 [auto-version-bump] 2026-10-20 11:27:52 +02:00
Ein Anderssono b7cd73f9eb Keep worker publish errors structured
Build and publish rule engine / release (push) Failing after 10s
2026-10-20 11:27:39 +02:00
10 changed files with 124 additions and 9 deletions
+14 -1
View File
@@ -19,6 +19,16 @@ jobs:
token: ${{ secrets.GITEA_TOKEN }}
persist-credentials: true
- name: Check release credentials before changing the version
shell: bash
env:
HARBOR_USERNAME: ${{ secrets.HARBOR_USERNAME }}
HARBOR_PASSWORD: ${{ secrets.HARBOR_PASSWORD }}
run: |
set -euo pipefail
test -n "$HARBOR_USERNAME" || { echo 'Missing HARBOR_USERNAME action secret'; exit 1; }
test -n "$HARBOR_PASSWORD" || { echo 'Missing HARBOR_PASSWORD action secret'; exit 1; }
- name: Test and lint in the shared builder image
shell: bash
run: |
@@ -115,8 +125,11 @@ jobs:
echo 'NATS is not installed yet. The backend release pipeline bootstraps NATS and this Argo Application.'
exit 0
fi
if ! kubectl -n argocd get application ai-spel-rule-engine >/dev/null 2>&1; then
echo 'The backend release pipeline owns first-time Argo Application creation; skipping this worker-only rollout.'
exit 0
fi
kubectl -n ai-spel rollout status statefulset/ai-spel-nats --timeout=10m
kubectl -n argocd apply -f deploy/argocd/application.yaml
kubectl -n argocd patch application ai-spel-rule-engine --type merge -p "{\"spec\":{\"source\":{\"targetRevision\":\"$version\"}}}"
deadline=$((SECONDS + 600))
while (( SECONDS < deadline )); do
Generated
+1 -1
View File
@@ -13,7 +13,7 @@ dependencies = [
[[package]]
name = "ai-spel-rule-engine"
version = "0.1.0"
version = "0.1.4"
dependencies = [
"async-nats",
"axum",
+1 -1
View File
@@ -3,7 +3,7 @@ members = ["crates/rule-engine"]
resolver = "2"
[workspace.package]
version = "0.1.1"
version = "0.1.4"
edition = "2024"
license = "MIT"
+12 -1
View File
@@ -8,7 +8,8 @@ remains responsible for validating and committing effects.
## Contract
Requests use NATS subject `ai-spel.rules.evaluate.v1` and contract version 1.
The canonical JSON Schema is `contracts/rule-evaluation-v1.schema.json`.
The canonical JSON Schema is `contracts/rule-evaluation-v1.schema.json`; its
versioned `$id` is updated by the release version-bump workflow.
Responses echo the correlation ID and have status `evaluated` or `rejected`.
The NATS user may subscribe only to the evaluation subject and publish only to
@@ -21,3 +22,13 @@ For source development, the Rust commands are `cargo fmt --all -- --check`,
`cargo test --workspace`, and `cargo clippy --workspace --all-targets -- -D warnings`.
Production builds, tests, image builds, and executable verification for this
project are run by Gitea Actions on the existing `large` runner and Kubernetes.
## Release deployment boundary
The API repository owns first-time NATS and Argo Application provisioning. The
worker release pipeline publishes this repository's versioned image and chart,
then updates the existing `ai-spel-rule-engine` Argo Application. It uses the
`AI_SPEL_TEST_KUBECONFIG` repository action secret, scoped to patch that one
Argo Application and read rollout health in namespace `ai-spel`. The one-time
service-account roles are described in `deploy/ci/namespace-scoped-rbac.yaml`;
they do not grant database, secret, workload-write, or cluster-wide access.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://gitea.k3s.k0.nu/ai-spel/ai-spel-rule-engine/raw/tag/v0.1.0/contracts/rule-evaluation-v1.schema.json",
"$id": "https://gitea.k3s.k0.nu/ai-spel/ai-spel-rule-engine/raw/tag/v0.1.4/contracts/rule-evaluation-v1.schema.json",
"title": "AI Spel Luau rule evaluation contract v1",
"type": "object",
"additionalProperties": false,
+1 -1
View File
@@ -83,7 +83,7 @@ async fn respond(client: Client, reply: Subject, payload: Vec<u8>) {
if let Err(error) = client.publish(reply, payload.into()).await {
eprintln!(
"{{\"level\":\"error\",\"event\":\"rule.reply_publish_failed\",\"error_category\":\"nats_publish\",\"detail\":{:?}}}",
error.to_string()
error
);
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ spec:
source:
repoURL: harbor.k3s.k0.nu/ai-spel
chart: ai-spel-rule-engine
targetRevision: "0.1.1"
targetRevision: "0.1.4"
helm:
releaseName: ai-spel-rule-engine
destination:
+66
View File
@@ -0,0 +1,66 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ai-spel-rule-engine-deployer
namespace: argocd
---
apiVersion: v1
kind: Secret
metadata:
name: ai-spel-rule-engine-deployer-token
namespace: argocd
annotations:
kubernetes.io/service-account.name: ai-spel-rule-engine-deployer
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ai-spel-rule-engine-deployer
namespace: argocd
rules:
- apiGroups: [argoproj.io]
resources: [applications]
resourceNames: [ai-spel-rule-engine]
verbs: [get, patch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ai-spel-rule-engine-deployer
namespace: argocd
subjects:
- kind: ServiceAccount
name: ai-spel-rule-engine-deployer
namespace: argocd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ai-spel-rule-engine-deployer
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ai-spel-rule-engine-deployer
namespace: ai-spel
rules:
- apiGroups: [apps]
resources: [deployments, replicasets, statefulsets]
verbs: [get, list, watch]
- apiGroups: [""]
resources: [pods, events]
verbs: [get, list, watch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ai-spel-rule-engine-deployer
namespace: ai-spel
subjects:
- kind: ServiceAccount
name: ai-spel-rule-engine-deployer
namespace: argocd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ai-spel-rule-engine-deployer
+2 -2
View File
@@ -2,5 +2,5 @@ apiVersion: v2
name: ai-spel-rule-engine
description: Isolated, sandboxed Luau proposal evaluator
type: application
version: 0.1.1
appVersion: "0.1.1"
version: 0.1.4
appVersion: "0.1.4"
+25
View File
@@ -9,9 +9,22 @@ match = re.search(r'(?ms)(^\[workspace\.package\]\s+.*?^version\s*=\s*")(\d+)\.(
if not match:
raise SystemExit("Missing [workspace.package].version")
major, minor, patch = map(int, match.group(2, 3, 4))
current_version = f"{major}.{minor}.{patch}"
version = f"{major}.{minor}.{patch + 1}"
cargo_path.write_text(cargo[:match.start(2)] + version + cargo[match.end(4):])
lock_path = Path("Cargo.lock")
lock = lock_path.read_text()
lock_pattern = rf'(?ms)^\[\[package\]\]\nname\s*=\s*"ai-spel-rule-engine"\nversion\s*=\s*"{re.escape(current_version)}"'
if not re.search(lock_pattern, lock):
raise SystemExit(f"Missing ai-spel-rule-engine {current_version} package in {lock_path}")
lock_path.write_text(re.sub(
lock_pattern,
f'[[package]]\nname = "ai-spel-rule-engine"\nversion = "{version}"',
lock,
count=1,
))
for path, pattern in (
(Path("deploy/helm/ai-spel-rule-engine/Chart.yaml"), r'(?m)^version:\s*\d+\.\d+\.\d+\s*$'),
(Path("deploy/helm/ai-spel-rule-engine/Chart.yaml"), r'(?m)^appVersion:\s*"\d+\.\d+\.\d+"\s*$'),
@@ -24,4 +37,16 @@ for path, pattern in (
f'appVersion: "{version}"' if pattern.startswith(r'(?m)^appVersion') else f' targetRevision: "{version}"'
)
path.write_text(re.sub(pattern, replacement, contents, count=1))
schema_path = Path("contracts/rule-evaluation-v1.schema.json")
schema = schema_path.read_text()
schema_pattern = r'(?m)^ "\$id": "https://gitea\.k3s\.k0\.nu/ai-spel/ai-spel-rule-engine/raw/tag/v\d+\.\d+\.\d+/contracts/rule-evaluation-v1\.schema\.json",$'
if not re.search(schema_pattern, schema):
raise SystemExit(f"Missing versioned schema id in {schema_path}")
schema_path.write_text(re.sub(
schema_pattern,
f' "$id": "https://gitea.k3s.k0.nu/ai-spel/ai-spel-rule-engine/raw/tag/v{version}/contracts/rule-evaluation-v1.schema.json",',
schema,
count=1,
))
print(version)