Highlights
apic 0.2.4 is a validation and security release. apic validate can now enforce a project-wide contract baseline from .apic/template.json, path handling is hardened against symlink escapes, and command output no longer leaks your home directory path. It also includes an internal visibility cleanup with no change in behavior.
Added
Template conformance in apic validate
apic validate now checks every contract against .apic/template.json, in addition to the existing JSON-schema validation. The template is treated as a partial: only the sections it actually declares are enforced, and a contract may always carry more than the template requires.
What is checked, for each section the template declares:
- Headers, every header name in the template must be present on the contract. Names are compared case-insensitively, so
content-typesatisfiesContent-Type. url.protocolandurl.host, must match the template's values exactly, so every contract shares one base URL.url.path,url.query,url.variable, each declared path segment and each query or variable name must be present on the contract.requestandresponsesschemas, every field name the template declares must be present, descending into nestedpropertiesand reported with a dotted path such asdata.id. Responses are matched by statuscode.
Violations are reported per contract on the FAIL line, for example:
FAIL contracts/login.json: missing header `Authorization`; url.host must be `api.example.com` (found `staging.internal`); response 200 schema missing field `data.id`
.apic/ is now excluded from the validate scan, so a partial template is never itself validated as a contract. The template still has its own dedicated check via apic validate --template.
Note: the default seeded .apic/template.json is a full example contract with placeholder values. Trim it down to your real baseline before relying on conformance, otherwise contracts are checked against those placeholders.
Security
Symlink-aware path confinement
Path confinement previously checked only the lexical shape of a path, so a symlinked component pointing outside the working directory could redirect a write. For example, with contracts/link symlinked to a directory outside the project, apic create -f link/escaped.json would create the file outside the configured root.
confine_to_dir now rejects any path whose component is a symlink, closing the bypass for apic create, apic convert --destination, and apic remove, all of which route through it. New files whose final component does not exist yet, the normal create case, are unaffected. This resolves the report in #22.
Home directory hidden in output
Absolute paths printed by apic could disclose your username and full filesystem layout, for example Created /home/alice/work/contracts/auth/login.json. The home directory prefix is now collapsed to ~ across command output, including the Created line and error messages. Paths outside your home directory, such as /tmp, are left intact since they carry no user-identifying information.
Changed
Internal visibility cleanup
Item visibility across the crate was tightened: pub was narrowed to pub(crate), and helpers used within a single module were made private. The unreachable_pub lint is now enabled as a guardrail so over-broad visibility cannot creep back in. This is an internal change with no effect on behavior or the command-line interface.
Documentation
- README prose now uses commas in place of em-dashes.
Install
From crates.io:
cargo install apic-cli
Or download a prebuilt binary for your platform from the assets below, verify it against the matching .sha256, and place apic on your PATH.
Full changelog
See CHANGELOG.md. Compare against the previous release: v0.2.3...v0.2.4