Skip to content

Capabilities

The status of each part on the two permanent platforms, against the ports and adapters design (0026 to 0034). A cell reads for master; the changelog dates each change. The adapters are in the generated adapters.

Mark Meaning
📄 designed: a record or specification exists, nothing is built
🧪 built: code exists and is tested, not yet released as a supported way to run
✅ supported: released, documented and covered by CI
n/a not applicable on this platform

Ports and adapters

The presets server, k8s-minimal and k8s-openbao are unavailable; aws-serverless, aws-hybrid and k8s-aws are available.

Piece Kubernetes AWS Lambda
Ports as Go interfaces (internal/port) and the apps depending on them ✅ ✅
Domain stores on the ports: workspaces and credentials, GitHub organisations and Apps, a person's GitHub link (the token pair in Secrets, compare-and-swap refresh), runner and catalogue Apps, the Slack records, the console's session key (internal/portstore; any ports.adapter but legacy, which needs a Secrets adapter) ✅ ✅
Secrets in OpenBao (adapters.secrets: openbao, compare-and-swap by KV cas) 🧪 🧪
Export: copies of the secrets the console keeps (retired by 0041: a consumer reads the typed document at external/<kind>/<id>, exports) retired retired
Export: the External Secrets PushSecrets of the chart (slackApps[].push, directory.push, githubApps.push, githubApps.catalogue[].push, slackState.push; need config.store: kubernetes) deprecated, replaced by the above n/a
Inputs: mounted ConfigMaps and Secrets ✅ n/a
Inputs: the configuration layer, or a parameter store n/a ✅
Port conformance suite: in-memory and legacy ✅ n/a
Port conformance suite: DynamoDB (LocalStack and an in-memory fake of the API; migrate into and out of it) ✅ ✅

Runtime

Piece Kubernetes AWS Lambda
Issuer, console and directory hub ✅ ✅
GitHub reconciler ✅ (one replica; two with a DynamoDB State, 🧪) ✅
Slack reconciler ✅ (one replica; two with a DynamoDB State, 🧪) ✅
Tick(target) with a lease per target, a report per target, and a trigger that ticks only its target (on the legacy adapter: the lease is exclusive across pods only with a shared State, and a controller has none; the console reaches a controller through the mounted records, polled) 🧪 📄
Two replicas of a reconciler 🧪 (chart replicas: refused unless ports.adapter is dynamodb) n/a
Slack Connect handoff: the host's tick notifies the guest's; the guest-side probe is the host's tick's 🧪 📄
Slack Connect handoff by pending-share record (share.<host>.<channel>: 14 days while pending, 7 days once accepted; needs a State both runners share) 🧪 📄
Slack users.info cache on the State (cache.slack.user.<workspace>.<id>, 24 h; slack_roster.user_cache counts hits and misses) 🧪 📄
Shared inputs of the Slack controller in the State (cache.<digest>.<name>) 📄 (stays in memory) 📄
Controllers reading the console's records from the State instead of mounted files (ports.adapter other than legacy) 🧪 📄
A function per module on Lambda: the issuer and console behind an API Gateway HTTP API, and github, slack, google, cloudflare, backup and restore, each with its own role; the controllers' ticks from EventBridge Scheduler (v1.76, 0071) n/a ✅
Server binaries, one per module and pinned at build (v1.76, 0071): sluis-issuer, sluis-github, sluis-slack, sluis-google, sluis-cloudflare, sluis-backup, sluis-outline (0077); sluis issuer runs a module in-process where its remote is unset; tick <github|slack> <target> runs one tick once; migrate --from <config> --to <config> copies the State between storages ✅ ✅
One chart sluis: a Deployment per module, the issuer and each enabled modules.<m>; backup.enabled adds the CronJobs 🧪 n/a
One service document (sluis/v3) validated against a schema ✅ ✅

Identity

Mechanism Kubernetes AWS Lambda
Verify a ServiceAccount token (a cluster declared in the installation) ✅ 📄
Verify an AWS outbound-federation token (sts:GetWebIdentityToken) ✅ ✅
Give the service an AWS identity (annotation or Pod Identity on the ServiceAccount) ✅ n/a
The function role's identity to an OTLP endpoint (the extension layer) n/a ✅

The federation verifier is the same code on both platforms.

Migration and operations

Piece Kubernetes AWS Lambda
sluis migrate --from <config> --to <config>: every domain store through its business interface, with --dry-run, create-if-absent and --overwrite, a plan before any write, and a read-back verification reported as JSON (operations/migrate.md) 🧪 📄
The backup module on layout v5 (0073): one age-encrypted tar.gz per backup in an archive bucket, retention, sluis backup verify, and a restore as a second deployment of the binary ✅ (CronJobs, a Job) ✅ (NewBackup, NewRestore)
Copy of Valkey sessions, refresh tokens and the keyring schedule into the new store, each with its remaining lifetime 🧪 n/a
Rollback by the same command in the other direction (--from dynamodb --to legacy) 🧪 n/a
Existing backup: a copy of named Secrets ✅ n/a

Telemetry

Piece Kubernetes AWS Lambda
Metrics over OTLP, configured by OTEL_* ✅ ✅
The chart sets the OTEL_* environment on every pod from telemetry.otlp (endpoint, protocol, a service name per component, extra OTEL_*); unset renders nothing 🧪 n/a
Platform logs over OTLP (observability's otlp-lambda layer) n/a ✅
Traces: HTTP and Connect spans, a span per tick, per port call, per module call and per AWS SDK call, the trace continued into the console and across a module call; the Lambda server span carries faas.invocation_id 🧪 🧪
Metrics: the issuer's requests, tokens, sign-ins and keys; ticks and leases; port calls; rate limits (reference/telemetry.md) 🧪 ✅
Chart modes renders: alerts and renders: dashboards: twelve rules, unit-tested with vmalert-tool, and a dashboard held to dashboardlint 🧪 n/a
No personal data in a span: an allowlist exporter, tested by planting markers; no person or group in a label 🧪 🧪

Telemetry is configured by the OTEL_* variables only (0032); see telemetry and Lambda.