feat(config): C3a — healthcheck/dependsOn/hooks schema structs (spec 10/11) - #3
Merged
Conversation
…10/11) Add the declarative shape the saga/health/hooks chunks build on: - Service.Healthcheck (*Healthcheck): kind (oneof tcp/http/https/exec/ pg_isready/redis) + per-kind params + Compose-style duration strings (interval/timeout/startPeriod), validated as parseable Go durations. - Service.DependsOn ([]DependsOn): service + condition (oneof healthy/started). - Workspace.Hooks / Project.Hooks (Hooks): preUp/firstRun/postUp/postPull/ preDown lists of Hook (name/run/service/command argv/workdir/env/timeout/ retries/onFailure/once), with Hooks.IsZero() for cheap skipping. Structural validation only (validator/v10): a new `duration` validator plus oneof/duration/min render messages. Semantic rules — dependsOn target existence, "condition:healthy needs a healthcheck", run:exec requires a service, the firstRun ledger — belong to internal/health (C3b) and internal/hooks (C4), not here. The valid testdata workspace now exercises every new field (seeds the config-conformance golden); generate ignores them until C3c, so determinism and smoke stay green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gustavobertoi
added a commit
that referenced
this pull request
Jun 29, 2026
#20) internal/dns owns the devstack block in /etc/hosts for resolving <service>.<project>.localhost on OS-resolver clients (the only consistently reliable mechanism cross-platform — spec 05 gotchas). All ops are idempotent and operate on an injectable path (fully temp-file-testable): - Block/Apply/Remove/Present/Missing: Apply replaces (or appends, or on absent creates) ONLY the fenced block — content outside the fence is never touched; Apply(nil) removes it; Remove restores the original byte-for-byte; the file's mode is preserved. - CLI `dns setup|status|remove` derives hostnames from the proxy route table (network.proxy.engine: caddy); writing /etc/hosts needs root, so a permission failure maps to a `sudo` remediation (per locked decision #3: build the logic, test with temp files, flag the human/sudo step). Unit tests (temp file): insert preserving original content, idempotent re-apply, replace-not-append, remove-strips-block-only + exact restore, Apply(nil) removes, Present/Missing diff, create-when-absent. CLI tests: registration + status reports the route host. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gustavobertoi
added a commit
that referenced
this pull request
Jun 29, 2026
internal/trust shells out to mkcert (NOT smallstep/truststore) to install/remove the local root CA and diagnose readiness, behind an injectable Runner so it is fully unit-testable without mkcert present: - Available / CARoot / Install (`mkcert -install`) / Uninstall (`mkcert -uninstall`) / Status. Status probes mkcert-on-PATH, the CAROOT rootCA.pem, certutil (Firefox/NSS), and WSL2, emitting the exact one-line remediation for whatever is missing (clean-Ubuntu certutil hint, WSL2 Windows-store import). - CLI `trust install|uninstall|status` replaces the stub. install/uninstall need sudo (mkcert writes system/NSS stores); status is read-only. Per locked decision #3: logic built + fake-runner tested, sudo flagged, Status is the self-verify probe (also feeds the doctor matrix in X6). Unit tests (fake runner + temp CAROOT): available detection, status across missing-mkcert / CA-not-installed / fully-ready / missing-certutil, install + uninstall call-through, missing-mkcert error, install error propagation. CLI: registration + read-only status. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gustavobertoi
added a commit
that referenced
this pull request
Jun 29, 2026
…(spec 05/13) (#33) Add a `trust (mkcert)` probe to `devstack doctor`: it reports local-CA readiness (mkcert on PATH, CAROOT rootCA.pem, certutil for Firefox/NSS) with the exact remediation, as a WARNING (local HTTPS is opt-in, so a missing CA never fails doctor). This is the decision-#3 self-verification for the sudo-gated trust feature (N2) and a step toward the full X6 doctor matrix + safe --fix. Test: doctor --json lists the trust probe. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 task
gustavobertoi
added a commit
that referenced
this pull request
Jun 29, 2026
…I (spec 04) (#64) Adds the `aws-sm` and `aws-ssm` provider kinds. It shells out to the `aws` CLI (NOT aws-sdk-go) — the same anti-bloat reasoning that keeps SOPS on its binary (DECISIONS): the SDK would pull a large cloud tree into the CGO_ENABLED=0 static binary. Shelling also inherits the user's AWS config / SSO / IAM-role creds the way git inherits SSH, so no AWS credential passes through devstack. - `aws-sm`: `get-secret-value` per distinct secret id (batched across refs that share an id); a keyless ref takes the raw SecretString, a `#dot.key` ref parses it as JSON and walks the path. - `aws-ssm`: ONE batched `get-parameters --with-decryption` for all referenced names; `--names` kept last (variadic) so `--region` isn't swallowed; any InvalidParameters → a clear error; optional `#key` walks a JSON-valued param. - `--region` from cfg.Region/Opts["region"]; empty lets the CLI resolve it. - Registered in RegisterBuiltins alongside sops; config passes the kind through (no allowlist), so it's declarable in workspace.yaml exactly like sops. Stdlib-only (no new deps). Unit-tested with a fake `aws` runner: SM keyless + JSON-key, per-secret batching (one call), SSM batched + region passthrough, invalid-parameter error, missing-CLI error, builtin registration. Account-gated (decision #3): logic + fakes here; real creds/localstack are a flagged human/integration step, not run in the nightly. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gustavobertoi
added a commit
that referenced
this pull request
Jun 29, 2026
…) — M4 secrets COMPLETE (#67) Adds the `infisical` provider kind, mirroring S2/S3: shells to the `infisical` CLI (not the Go SDK — anti-bloat, DECISIONS) and inherits the user's auth (`infisical login` / INFISICAL_TOKEN), so no credential passes through devstack. The environment is exported ONCE (`infisical export --format=json`, batched) with optional --projectId/--env/--path, then each ref's key is extracted; a #key walks a JSON-valued secret. Export-format drift across Infisical versions is handled by tolerant parsing: accepts both a flat {KEY:VALUE} object and a list of {key/secretKey, value/secretValue} records. Fake-runner tested for both shapes + JSON #key + missing-secret + missing-CLI + builtin registration. Account-gated (decision #3): logic + fakes here; the exact CLI version/contract is a flagged owner-verify step, not run in the nightly. Stdlib-only (no new deps). This completes M4: S1 (core) · S2 (SOPS+age) · S3 (AWS SM/SSM) · S4 (Infisical) · S5 (keyring login) · S6 (post-render inject + leak test). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Chunk C3a (M2-remainder)
Adds the declarative config structs that C3b (health), C3c (generate emits
healthcheck:), and C4 (hooks runner) build on — structs + structural validation only, per specs 10 & 11.What
Service.Healthcheck(*Healthcheck, nil = none):kind(oneoftcp/http/https/exec/pg_isready/redis) + per-kind params + Compose-style duration strings (interval/timeout/startPeriod) validated as parseable Go durations.Service.DependsOn([]DependsOn):service+condition(oneofhealthy/started).Workspace.Hooks/Project.Hooks(Hooks):preUp/firstRun/postUp/postPull/preDownlists ofHook(name/run/service/command-argv/workdir/env/timeout/retries/onFailure/once), withHooks.IsZero().Deliberately deferred (not this chunk)
Semantic rules live in their owning packages, not in config:
dependsOntarget existence + "condition: healthyneeds a healthcheck" →internal/health(C3b/X2);run: execrequires aservice+ thefirstRunledger →internal/hooks(C4).Tests
TestLoadValidnow asserts the new fields parse (the valid testdata exercises every one — seeds the config-conformance golden).durationvalidator +oneof/duration/minerror rendering.Gate
make ci+make determinism+make smokegreen.generateignores the new fields until C3c, so output stays byte-deterministic.🤖 Generated with Claude Code