Skip to content

Latest commit

 

History

History
126 lines (115 loc) · 10.5 KB

File metadata and controls

126 lines (115 loc) · 10.5 KB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Added

  • CLI skeleton with reconcile and validate subcommands
  • Global flags: --json, --insecure-tls
  • RESTIUM_* environment variable support for all flags
  • Exit code convention: 0 (success), 1 (runtime error), 2 (input/validation error)
  • Structured logging with JSON (--json) and human-readable text modes
  • Automatic secret redaction for sensitive key-value pairs (authorization, token, password, api_key, client_secret, etc.)
  • URL query parameter redaction for secrets in logged URLs
  • YAML spec file parsing with global settings and resources list
  • Global settings inheritance: base_url, default_headers, auth (with per-resource override)
  • Structured payloads (nested objects, arrays) preserved through YAML-to-JSON
  • depends_on field for explicit resource ordering
  • deny_unknown_fields on spec types for typo detection
  • AuthConfig type definitions (bearer, basic, api_key, oidc, mtls) — type stubs for Epic 2
  • validate and reconcile commands now parse and report spec file contents
  • Spec validation: reference checking (${resource.output.field}), duplicate resource name detection, circular dependency detection
  • validate command reports ALL errors (not just the first), exits with code 2 on validation failure
  • Dependency graph module (src/graph/mod.rs) with petgraph-based topological sort and cycle detection
  • DependencyGraph::build() merges explicit depends_on and implicit ${resource.output.field} references into a single DAG
  • DependencyGraph::topological_sort() returns execution order or cycle path error
  • Reconcile module (src/reconcile/) with state discovery, diff computation, and action determination
  • ResourceAction enum: Create, Update, Skip, Delete
  • Key-order-independent JSON comparison (json_equal) for idempotent reconciliation
  • State discovery via GET with 404 handling (resource does not exist → Create)
  • Resource execution module (src/reconcile/execute.rs) for create/update/skip operations
  • Actionable error messages with resource name, HTTP method, endpoint, status code, and hints
  • Error hints for common HTTP status codes (401, 403, 404, 409, 422, 429, 5xx)
  • Update operations auto-switch from POST to PUT when resource method is POST
  • Explicit resource deletion via action: delete with DELETE HTTP request
  • Delete of absent resource (404) logged as "already absent" and skipped
  • Reconcile command orchestration: parse → graph → sort → for each resource: resolve refs → discover state → compute diff → execute → extract outputs
  • Reconciliation summary logged on completion (created, updated, deleted, skipped, failed counts)
  • Delete resources processed in reverse topological order (dependents deleted before dependencies)
  • Exit code 1 on reconciliation failure, exit code 0 on success
  • Reference module (src/reference/mod.rs) for output extraction and ${resource.output.field} resolution
  • OutputStore type for storing extracted outputs across resources
  • extract_outputs() extracts fields from API responses (string, number, bool, null, complex)
  • resolve_references() recursively substitutes template references in JSON payloads
  • resolve_string() resolves references in individual strings (endpoints, read_endpoints)
  • HTTP client wrapper (HttpClient) with configurable TLS via ureq + rustls
  • TLS certificate verification enabled by default (webpki roots)
  • --insecure-tls flag skips certificate verification (explicit opt-in, NFR3)
  • Custom CA bundle support via ca_bundle field in global config
  • AuthProvider trait for pluggable authentication strategies
  • Bearer token authentication via token_env environment variable
  • Basic auth (username/password) via environment variables with base64 encoding
  • Auth provider factory (create_auth_provider) for config-driven provider selection
  • API key authentication via header or query parameter mode
  • OIDC/OAuth2 client credentials authentication (token fetched at startup via POST to token endpoint)
  • mTLS client certificate authentication via client_cert_path and client_key_path
  • mTLS works in combination with custom CA bundles
  • Per-resource auth override: resources can specify their own auth config, overriding global auth
  • Shared read_env_credential helper validates env vars are set, non-empty, and UTF-8 across all auth providers
  • --sidecar flag (and RESTIUM_SIDECAR env var) to keep the process alive after reconciliation completes — for K8s sidecar container deployments where the container must not exit
  • Distroless Docker image (FROM scratch) with multi-stage build — 3.5MB, zero CVEs, non-root user
  • Multi-arch container support (linux/amd64, linux/arm64) via Docker buildx with QEMU in release pipeline
  • make cross target for local musl cross-compilation via cargo-zigbuild
  • make docker-multiarch target for local multi-arch Docker builds
  • CI pipeline (GitHub Actions): fmt check, clippy with --all-targets, test, build on every PR and push to main
  • Release pipeline: automated cargo publish + multi-arch GHCR push on version tags, with SBOM and provenance
  • Auto-tag workflow: automatically creates git tags when Cargo.toml version changes on main
  • Comprehensive README with value proposition, quick start, Netbird example, spec reference, auth docs, security posture, CLI reference, and deployment guide
  • Example spec files: examples/simple.yaml (minimal), examples/netbird.yaml (real-world Netbird bootstrapping)
  • Helm chart (charts/restium/) for K8s Job deployment with ConfigMap-mounted spec and Secret-based credentials

Changed

  • validate command no longer creates an HTTP client (pure syntax/semantic validation)
  • Spec file loading uses SpecFile::load error directly instead of redundant existence check
  • Validation now scans endpoint field for template references (previously only payload and read_endpoint)
  • Cycle detection replaced from manual DFS to petgraph-based implementation via DependencyGraph
  • Reference extraction functions (extract_refs_from_string, extract_references_from_value) made public for reuse by graph module
  • --insecure-tls and mTLS client certificates are now mutually exclusive (previously mTLS cert was silently dropped)
  • Lint target now includes test code (cargo clippy --all-targets)
  • Test fixture paths use CARGO_MANIFEST_DIR for CWD-independent test execution
  • HttpClient::get() now accepts auth: Option<&dyn AuthProvider> for consistency with send_json() and request()
  • NoVerifier::supported_verify_schemes() caches signature schemes via LazyLock instead of re-instantiating CryptoProvider per TLS handshake
  • mTLS file validation deferred to HttpClient::new() — removed redundant metadata() check from MtlsAuthProvider::new() to eliminate TOCTOU window
  • OidcAuthProvider::with_token() marked #[doc(hidden)] (testing escape hatch, not public API)
  • auth::mtls and auth::oidc submodules changed from pub mod to mod (types re-exported via pub use)
  • OIDC token request now uses the configured HttpClient agent (inherits TLS settings: custom CA bundle, --insecure-tls)
  • create_auth_provider() accepts optional &ureq::Agent for OIDC TLS configuration
  • HttpClient::agent() method exposes the underlying ureq Agent for auth provider use
  • DependencyGraph::build() uses update_edge instead of add_edge to prevent duplicate edges when explicit and implicit deps overlap
  • MtlsAuthProvider simplified to unit struct — cert/key paths extracted from AuthConfig directly, not stored redundantly on the provider
  • execute_action returns ExecuteResult enum (Performed/AlreadyOk) instead of Option<Value> — allows callers to distinguish successful operations from skips/already-absent
  • Success log in execute_mutation moved after response body parse (previously logged success before JSON parse could fail)
  • Non-JSON 2xx responses treated as success with no body (previously hard-failed as invalid JSON)
  • Update method auto-switch uses case-insensitive comparison (eq_ignore_ascii_case("POST"))
  • error_hint checks transport errors before HTTP status codes to avoid false matches on URL digits
  • Delete 404 ("already absent") now increments skipped counter instead of deleted
  • State discovery GET skipped when resource has no payload (previously wasted a network request)

Security

  • OIDC error messages no longer expose client_secret — controlled error formatting instead of raw ureq error propagation
  • OIDC error messages now extract OAuth error fields (error, error_description) from the response body for actionable diagnostics
  • Auth providers (Bearer, Basic, ApiKey, OIDC) now implement custom Debug that redacts credentials instead of using #[derive(Debug)]
  • Empty env var values rejected with actionable error (previously silently sent empty credentials)
  • VarError::NotUnicode now produces distinct error message instead of misleading "not set"
  • API key auth validates header_name and query_param are non-empty

Fixed

  • process_delete_resource now resolves ${resource.output.field} template references in endpoints (was using raw template strings, causing 404s or wrong-resource deletion)
  • execute_mutation now propagates JSON parse errors from API responses instead of silently substituting null
  • Spec validation rejects unknown action values (only delete is supported; previously any string was silently treated as create/update)
  • OIDC url_encode renamed to form_url_encode and uses + for spaces (HTML form encoding per RFC 1866) instead of %20 (RFC 3986), fixing multi-word scope values on strict token endpoints
  • OIDC token_url is now validated as non-empty before making the HTTP request
  • Redundant "Error:" prefix in spec file not found message (logger already prepends [ERROR])
  • format! + push_str replaced with write! to avoid unnecessary allocations in OIDC URL encoding and text log formatting
  • Misleading // Safety: comment changed to // Note: (not an unsafe block)
  • JSON log fallback replaced with expect() (serialization of BTreeMap<String, Value::String> is infallible)
  • Unnecessary body.clone() removed in HttpClient::send_json (reference already satisfies Serialize)
  • Malformed template references like ${.output.field} (empty resource name) are now silently ignored instead of producing confusing errors
  • Use sort_unstable() instead of sort() for primitive &str slice in cycle detection