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.
- Release workflow:
cargo publishfailed whenCargo.lockwas stale. Added an explicitcargo update --workspacestep before publish to ensure lockfile consistency.
database.default_databasefield for structured config: specifies which database to connect to duringcreate_if_missingbootstrap. Defaults topostgresfor PostgreSQL; MySQL connects without selecting a database. Useful when the user does not have access to the defaultpostgresdatabase.
- Structured database config now works with
create_if_missing: truewhen the target database does not yet exist. Previously, the initial connection included the non-existent database name, causing an immediate connection error. Now initium connects to a bootstrap database first, creates the target, then reconnects. Fixes #50.
- Added integration tests for structured database connectivity: special-character passwords (URL-reserved chars like
@,:,/,?,#,%), PostgreSQLoptionsfield (connect_timeout), andcreate_if_missingwith non-existent database (#50). - Release workflow: replaced QEMU-emulated multi-arch Docker builds with native cross-compilation using
cargo-zigbuild+sccache. Build time reduced from ~50 minutes to ~8-12 minutes. - Release workflow: split into parallel
test,build(matrix: amd64 + arm64),docker, andpublishjobs. Crates.io publish now runs after Docker images are pushed. - CI workflow:
buildjob now cross-compiles for both amd64 and arm64 usingcargo-zigbuild+sccache, warming the cache for release builds. - Dockerfiles (
Dockerfile,Dockerfile.jyq): replaced multi-stage Rust build with minimal images that COPY pre-built binaries. No more in-Docker compilation. - Switched
mysqlcrate fromnative-tls(OpenSSL) torustls-tls, eliminating the OpenSSL dependency entirely. Binary size stays at ~5 MB. - Makefile: added
cross-buildanddocker-multiarchtargets for local multi-arch builds. - README: added Development section with cross-compilation and sccache setup instructions.
- SBOM attestation in release workflow: use platform-specific SBOM path (
index .SBOM "linux/amd64") instead of.SBOM.SPDXwhich returnsnullfor multi-platform images. - Cosign verification commands in docs and Makefile: use
--certificate-identitywith the exact tag ref (e.g.@refs/tags/v2.0.0) instead of a glob pattern (v*) which cosign does not support.
- Cosign keyless image signing in release workflow for both
initiumandinitium-jyqcontainer images. Images are signed using Sigstore OIDC via GitHub Actions. SBOM attestations are also signed and attached to each image. - Added
make verify-imagetarget to verify cosign signatures locally.
urlencodetemplate filter for percent-encoding strings in URLs. Useful for embedding passwords or other values containing URL-reserved characters (@,%,:,/, etc.) in connection strings.- Structured database connection config as an alternative to URL (
host,port,user,password,name,optionsfields). Passwords with URL-reserved characters (@,%,:, etc.) work without encoding. Connections are built using driver-native APIs (PostgreSQL key-value DSN, MySQLOptsBuilder), bypassing URL parsing entirely. Theurl/url_envfields remain supported for backward compatibility. See #39.
migratesubcommand: removed the thin command-execution wrapper. Useexecsubcommand instead if you need to run an external migration tool with structured logging.
- Renamed
jyq.DockerfiletoDockerfile.jyqto follow theDockerfile.<variant>convention. - Docker dependency cache now survives version-only bumps by normalizing the root package version in a preparatory build stage.
- Reject unsupported
optionsfield in MySQL structured config — MySQLOptsBuilderdoes not support arbitrary connection options.
dprintformatter for Markdown, JSON, TOML, YAML, and Dockerfile with CI check (dprint/check@v2.2) and definition-of-done gate.- YAML plugin for
dprintformatter. - Render tests now use an RAII
EnvGuardto restore environment variables on drop, preventing cross-test interference when tests run in parallel. EnvGuardnow usesOsStringfor correctness and supportsremove()constructor for unsetting variables.
- Auto Tag workflow now uses
RELEASE_TOKENinstead ofGITHUB_TOKENso the pushed tag triggers the Release workflow. Tags pushed by the defaultGITHUB_TOKENdo not trigger other workflows (GitHub Actions security feature). - Added
RELEASE_TOKENpreflight check to Auto Tag workflow and removed unused environment variable.
- Auto-tag workflow: CI automatically creates a git tag when
Cargo.tomlversion changes on main, triggering the release workflow. /releaseskill for Claude Code: guided release preparation with version determination, confirmation, and PR creation.ignore_columnsoption for reconcile mode tables: columns listed inignore_columnsare included in the initial INSERT but excluded from change detection, UPDATE statements, and content hash computation. Useful for timestamps, tokens, or values managed by database triggers.
- Moved
/releasefrom Claude Code command to skill (directory-basedSKILL.mdformat).
- Replaced Dockerfile
--mount=type=cachewith dependency layer caching ("empty main" trick) for reliable Docker build caching in GitHub Actions, where--mount=type=cachedoes not persist across runners.
- Reconcile mode for seed sets (
mode: reconcile): declarative seeding where the spec is the source of truth. Changed rows are updated, new rows are inserted, and removed rows are deleted automatically. --reconcile-allCLI flag to override all seed sets to reconcile mode for a single run.--dry-runCLI flag to preview what changes reconciliation would make without modifying the database.- Per-row tracking table (
initium_seed_rows) for change detection and orphan deletion in reconcile mode. - Content hash (
content_hashcolumn) on the seed tracking table for fast "anything changed?" checks before row-by-row comparison. - Automatic migration of existing tracking tables: the
content_hashcolumn is added transparently on first run. Existing seed sets remain inoncemode with no behavior change. - CI summary job (
ci) for branch ruleset status check compatibility.
- Reconcile hash-skip now only applies to seed sets without
@ref:expressions. Seed sets containing@ref:references always run row-level reconciliation to prevent stale foreign keys when upstream auto-generated IDs shift. - Hash computation sorts tables by
(order, table_name)instead of justorderfor deterministic hashing when multiple tables share the same order value. - Dry-run mode treats
@ref:expressions as literals to avoid failures when references haven't been populated yet (e.g., auto_id + refs within the same seed set).
--reconcile-allnow rejects seed sets where any table is missingunique_key, preventing reconciliation from generating identical row keys and updating/deleting wrong rows.- Reconcile mode validation now rejects empty/whitespace-only
unique_keyentries and reserved column names like_ref. - Reconcile mode validation now checks that every row contains all
unique_keycolumns, preventing incomplete row keys during reconciliation. - MySQL row tracking table now uses SHA-256 generated column (
row_key_hash) for the primary key instead ofrow_key(255)prefix, preventing key collisions for JSON keys exceeding 255 bytes.
- Project scaffolding with Rust/Cargo, CLI framework (clap), and repo layout
wait-forsubcommand: wait for TCP and HTTP(S) endpoints with retries, exponential backoff, and jitterexecsubcommand: run arbitrary commands with structured logging, exit code forwarding, and optional--workdirfor child process working directoryfetchsubcommand andinternal/fetchpackage: fetch secrets/config from HTTP(S) endpoints with auth header via env var, retry with backoff, TLS options, redirect control (same-site by default), and path traversal preventionrendersubcommand andinternal/renderpackage: render templates into config files withenvsubst(default) and Jinja2 template modes, path traversal prevention, and automatic intermediate directory creationseedsubcommand: run database seed commands with structured logging and exit code forwarding- Structured database seeding via
seedsubcommand with YAML/JSON spec files - Seed tracking table (
initium_seedby default) for idempotent seed application - Support for PostgreSQL, MySQL, and SQLite database drivers
- Auto-generated IDs and cross-table references via
_ref/@ref:syntax - Environment variable substitution in seed values via
$env:VAR_NAME - Unique key detection to prevent duplicate row insertion
- Reset mode (
--reset) to delete existing data and re-apply seeds - Transaction safety: each seed set is applied atomically with rollback on failure
- Ordered seed sets and tables via
orderfield - Seed schema with phase-based execution: ordered phases with create → wait → seed lifecycle
- MiniJinja template rendering for seed spec files: dynamic values, conditionals, loops via
{{ env.VAR }} - Embedded database/schema creation via
create_if_missingin seed phases (PostgreSQL, MySQL) - Embedded wait-for logic: poll for tables, views, schemas, or databases with configurable per-phase and per-object timeouts
- Database trait methods:
create_database,create_schema,object_exists,driver_namefor SQLite, PostgreSQL, MySQL - Cross-phase
@ref:references: references defined in earlier phases resolve in later phases - Custom MiniJinja template filters:
sha256,base64_encode,base64_decodeavailable in all templates (render and seed spec files) sha256filter with optionalmodeparameter ("hex"default,"bytes"for byte array output)base64_encode/base64_decodefilters for standard Base64 encoding and decoding with error handling for invalid input- Filters are chainable: e.g.
{{ "data" | sha256 | base64_encode }} src/template_funcs.rsdedicated module for template utility functions, designed for easy extension- Duration unit support for all time parameters (
--timeout,--initial-delay,--max-delay, seed phasetimeout, seed wait-fortimeout): acceptsms,s,m,hsuffixes with decimal values (e.g.1.5m,2.7s) and combined units (e.g.1m30s,2s700ms,18h36m4s200ms); bare numbers default to seconds src/duration.rsmodule withparse_durationandformat_durationutilities- Environment variable support for all CLI flags via
INITIUM_*prefix (e.g.,--json→INITIUM_JSON,--timeout→INITIUM_TIMEOUT); flag values take precedence over env vars - Comma-separated
INITIUM_TARGETenv var for specifying multiple wait-for endpoints internal/retrypackage with configurable retry logic, backoff, and jitterinternal/loggingpackage with text and JSON structured logging, automatic secret redactioninternal/safetypackage with path traversal prevention for file writes- Dockerfile for multi-arch scratch-based builds (runs as non-root UID 65534)
jyq.Dockerfileandinitium-jyqcontainer image variant with pre-builtjqandyqtools- Makefile with build, test, lint, and Docker targets
- Helm chart skeleton with security-hardened initContainer templates
- GitHub Actions CI workflow (lint, test, build) and release workflow (container build/push with SBOM)
- FAQ.md with functionality, security, and deployment questions for junior-to-mid-level engineers
- Documentation: README, usage guide, security threat model, architecture/design docs, seeding guide, templating guide
- Documentation for building custom images using Initium as a base
- SECURITY.md with vulnerability reporting instructions
- Apache 2.0 LICENSE
- Examples for nginx-waitfor, postgres-seed, config-render, template-functions, and phased-seed use cases
- Unit tests for retry logic, logging, safety path validation, wait-for, sha256, base64, template integration, seed schema parsing, database operations, executor logic, references, idempotency, reset, edge cases, duration parsing, and env var support
- Integration tests with docker-compose for end-to-end testing against real Postgres 16, MySQL 8.0, and nginx services
- Helm chart unit tests using helm-unittest plugin covering deployment rendering, securityContext, and configuration
- Separate GitHub Actions workflow for integration tests with service containers
- Complete rewrite from Go to Rust for smaller Docker images (7.4MB → ~5MB)
- CLI framework changed from cobra to clap
- Template engine changed from Go text/template to minijinja (Jinja2-style); access env vars via
{{ env.VAR }} - CI/CD workflows updated for Rust toolchain (cargo test, clippy, rustfmt)
- Dockerfiles updated to use rust:1.88-alpine builder with musl static linking
- CLI time parameter defaults now use duration units:
--timeoutdefault5m(was300),--initial-delaydefault1s(was1000),--max-delaydefault30s(was30000); seed phase timeout default30s(was30) - Replaced
regexcrate with manual envsubst parser in render module for smaller binary - Replaced
chronocrate withstd::time::SystemTimeand Hinnant's civil calendar algorithm in logging module - Switched rustls from default crypto backends (aws-lc-rs + ring) to ring-only
- Disabled ureq default features (gzip/brotli) to reduce dependency tree
- Database drivers (sqlite, postgres, mysql) are now optional Cargo features (all enabled by default); build with
--no-default-features --features sqlitefor minimal binary - Seed executor tests now verify data actually arrived in the database after execution
- Clarified that seed phases with only
create_if_missingcan omit theseed_setsfield entirely (seed_setsdefaults to empty via#[serde(default)]) - Improved crates.io metadata: keyword-rich description,
rust-version = "1.88"MSRV, authors,documentationpointing to docs.rs, andexcludeto reduce published crate size - Added
#![doc = include_str!("../README.md")]tosrc/main.rsso docs.rs renders the README as the crate landing page - Release workflow now publishes to crates.io automatically on tag push (requires
CARGO_REGISTRY_TOKENsecret)
- Updated Dockerfiles (
Dockerfile,jyq.Dockerfile) fromrust:1.85-alpinetorust:1.88-alpineto fix release workflow failure caused bytime@0.3.47requiring rustc 1.88.0 - Aligned all markdown table columns across documentation files
- Fixed clippy
collapsible_iflint in seed executor's unique key check - Removed dead code: unused
src/cmd/seed.rsmodule (replaced bysrc/seed/) - Suppressed unused field warning on
AutoIdConfig.id_type(reserved for future use) - Removed unused imports (
Arc,Mutex) and unused mutable binding in seed executor tests - Added Cargo dependency caching (
Swatinem/rust-cache@v2) to all CI and release workflow jobs for faster builds - Added Docker BuildKit layer caching (
type=gha) to release workflow for both main and jyq image builds - Replaced Dockerfile stub-build caching layer with BuildKit
--mount=type=cachefor cargo registry and target directory, enabling cross-build cache reuse
- Seed schema version 1 (flat
seed_setswithout phases): all seed specs now use phase-based structure versionfield from seed spec schema: no longer required or accepted
- All file operations constrained to --workdir with path traversal prevention
- Automatic redaction of sensitive keys (token, password, secret, etc.) in logs
- Container runs as non-root with read-only root filesystem and all capabilities dropped