Skip to content

iter-19: pull-zone bug fixes & CLI UX polish#21

Merged
ractive merged 2 commits into
mainfrom
iter-19/pullzone-bugfixes
May 7, 2026
Merged

iter-19: pull-zone bug fixes & CLI UX polish#21
ractive merged 2 commits into
mainfrom
iter-19/pullzone-bugfixes

Conversation

@ractive

@ractive ractive commented May 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • BLOCKER fix: pull-zone create now supports --storage-zone-id (and --zone-tier {premium,volume}); a clap ArgGroup enforces exactly-one-of --origin-url / --storage-zone-id. pull-zone update adds --storage-zone-id (mutually exclusive with --origin-url).
  • BLOCKER fix: Forward-compatible repr-enum deserialization in bunny-api-core — every Option<EnumType> response field now falls back to None for unknown integers via serde_helpers::deserialize_repr_option. OriginType::MagicContainerEndpoint = 5 is now modelled, fixing the panic on Magic-Container-backed pull zones (pullzone get 5719318). DnsRecord.record_type is now Option<DnsRecordType> for the same reason.
  • BLOCKER fix: storage-zone get/list/create now surfaces Password / ReadOnlyPassword. Redacted by default (<set, length=N>); pass --reveal to bypass. Operators no longer have to fall back to curl for credential bootstrap.
  • UX polish: hoppy container list/get/delete now mirror pull-zone list etc. (alias to container app …); hoppy --version now embeds the short git SHA and bunny-spec date via a small build.rs; long-form help with examples on pull-zone create, pull-zone hostname add, dns record add, storage-zone create.
  • Docs: new entries in decision-log.md and api/bunny-api-quirks.md covering the lossy-enum strategy, the storage-password redaction, and the DNS Flatten/PullZone caveats; iter-19 plan marked completed with explicit deferrals.

Test plan

  • cargo fmt
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
  • New wiremock tests cover: pull-zone create --storage-zone-id body shape, --zone-tier volume body shape, ArgGroup error paths (no flag / both flags), pull-zone update --storage-zone-id, Magic-Container PZ regression fixture (OriginType: 5), unknown-OriginType fallback, storage-zone get redacted vs --reveal.
  • Manual: hoppy --version prints hoppy 0.1.0 (sha=…, bunny-api-spec=YYYY-MM-DD).
  • Live E2E (deferred — covered by wiremock; gated behind live-api feature for future runs).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Container shortcuts: container list, container get, container delete
    • Pull-zone create/update: mutually-exclusive --origin-url vs --storage-zone-id plus --zone-tier
    • Enhanced version output showing build SHA and API spec date
  • Improvements

    • Storage zone passwords included in JSON but redacted by default; --reveal to show plaintext
    • More resilient enum/DNS deserialization (unknown values become None)
    • Improved secret-redaction rules and CLI help/examples
  • Documentation

    • Knowledgebase and decision-log updated with these behaviors
  • Tests

    • Added CLI and regression tests covering new behaviors and edge cases

Fixes the two field-report blockers (Storage-Zone-backed pull-zone create,
deserialize panic on Magic-Container-backed pull zones) plus credential
bootstrap (storage-zone passwords) and a few polish items.

- pull-zone create: --storage-zone-id and --zone-tier flags, ArgGroup
  enforces exactly-one origin
- pull-zone update: --storage-zone-id (mutually exclusive with --origin-url)
- bunny-api-core: forward-compat repr-enum deserialization via lossy
  Option<T> helper; OriginType=5=MagicContainerEndpoint added
- DnsRecord.record_type now Option<DnsRecordType>
- storage-zone get/list/create: Password / ReadOnlyPassword surfaced via
  redaction layer (default `<set, length=N>`, --reveal opts in)
- container list/get/delete: top-level shortcuts aliasing `container app`
- hoppy --version: embeds short git SHA + bunny-spec date via build.rs
- help text: examples + long_help on pull-zone create, pull-zone hostname
  add, dns record add, storage-zone create

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Free

Run ID: 29ae0feb-aec0-4b41-99c5-8e0d685a21ba

📥 Commits

Reviewing files that changed from the base of the PR and between 9813b22 and ddbf1ce.

📒 Files selected for processing (5)
  • build.rs
  • crates/bunny-api-core/tests/pullzone_api.rs
  • src/redact.rs
  • tests/cli_pull_zone.rs
  • tests/cli_storage_zone.rs

📝 Walkthrough

Walkthrough

This PR implements forward-compatible enum deserialization, makes pull-zone creation support storage-zone backing with clap ArgGroup validation, threads storage-zone secret redaction through CLI output (with --reveal), embeds build provenance (git SHA and specs date) in version metadata, and updates tests, fixtures, and documentation.

Changes

Forward-compatible enums, storage-zone backing, and credential redaction

Layer / File(s) Summary
Build provenance
build.rs
Embeds git commit SHA and bunny-spec modification date into binary via cargo:rustc-env and rerun triggers.
Serde deserialization helper
crates/bunny-api-core/src/serde_helpers.rs, crates/bunny-api-core/src/lib.rs
Introduces deserialize_repr_option to map unknown serde_repr integer values to None for Option<Enum> fields; includes unit tests for known/unknown/null handling and round-trip behavior.
Type model resilience
crates/bunny-api-core/src/types.rs
Applies deserialize_repr_option to OriginType (adds MagicContainerEndpoint=5), EdgeRule trigger/action types, PullZone origin/zone type; makes DnsRecord.record_type optional and CreatePullZone storage-zone-aware.
API client tests & fixtures
crates/bunny-api-core/tests/*, fixtures/core/pullzone_get_magic_container.json
Updates DNS assertions for optional record types; adds Magic-Container regression tests and unknown OriginType fallback test; adjusts storage-zone serialization expectation and adds fixture.
CLI types and arguments
src/cli.rs
Adds LONG_VERSION with build metadata; introduces ZoneTier enum; reworks pull-zone create/update with clap ArgGroup for --origin-url vs --storage-zone-id mutual exclusivity; adds container subcommand shortcuts.
Command handlers
src/commands/pull_zone.rs, src/commands/container.rs, src/commands/dns.rs
Wires pull-zone create with origin_url or storage_zone_id selection; updates DNS handler for optional record_type; delegates container List/Get/Delete to existing app handlers.
Secret redaction
src/redact.rs, src/commands/storage_zone.rs, src/main.rs
Implements redact_secrets_in_json with field-name allowlist; threads RedactConfig through storage-zone handlers and print functions; applies redaction to JSON list/get/create outputs by default with --reveal bypass.
CLI integration tests
tests/cli_pull_zone.rs, tests/cli_storage_zone.rs
Adds async tests covering pull-zone create with --storage-zone-id and --zone-tier, local arg validation for missing/conflicting flags, pull-zone update storage backing, and storage-zone password redaction/reveal behavior.
Documentation
hoppy-knowledgebase/*
Documents repr-enum forward-compat behavior, pull-zone storage backing caveats, storage-zone plaintext password behavior with CLI redaction, DNS edge cases, decision-log entries, and iteration notes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A rabbit hops through enums wise,
With storage zones and redacted ties,
Forward-compat, no panic spree—
Build metadata sings in version glory! 🐰
Clap groups whisper "pick just one."


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses several CLI blockers and UX improvements in hoppy (the async Rust bunny.net CLI), focusing on pull zone creation/update correctness, forward-compatible enum deserialization in the core API client, and safely surfacing Storage Zone credentials via the existing redaction layer.

Changes:

  • Fix pull-zone create/update to support Storage-Zone-backed origins (--storage-zone-id) and add --zone-tier {premium,volume} with clap mutual-exclusion enforcement.
  • Make bunny-api-core more forward-compatible by lossy-deserializing unknown integer repr-enums to None, and model OriginType::MagicContainerEndpoint = 5.
  • Surface StorageZone.Password / ReadOnlyPassword in CLI JSON with default redaction (<set, length=N>) and --reveal override; plus --version provenance via build.rs and container command aliases.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/snapshots/cli_storage_zone__storage_zone_list_json.snap Snapshot updated to include redacted Password/ReadOnlyPassword fields.
tests/snapshots/cli_storage_zone__storage_zone_get_json.snap Snapshot updated to include redacted Password/ReadOnlyPassword fields.
tests/snapshots/cli_storage_zone__storage_zone_create_json.snap Snapshot updated to include redacted Password/ReadOnlyPassword fields.
tests/cli_storage_zone.rs Adds CLI tests for default redaction vs --reveal for storage-zone get.
tests/cli_pull_zone.rs Adds CLI tests for --storage-zone-id, --zone-tier, and clap ArgGroup error paths.
src/redact.rs Adds JSON secret-field redaction walker + updates secret-field heuristic.
src/main.rs Passes RedactConfig into storage-zone command handler.
src/commands/storage_zone.rs Applies secret redaction to storage-zone JSON output and threads RedactConfig through.
src/commands/pull_zone.rs Adds create/update support for StorageZoneId and zone tier mapping into request body.
src/commands/dns.rs Handles DnsRecord.record_type: Option<_> in table rows with “Unknown” fallback.
src/commands/container.rs Adds top-level container list/get/delete aliases to container app ....
src/cli.rs Adds ZoneTier enum, pull-zone ArgGroup, expanded help text, container aliases, and long --version.
hoppy-knowledgebase/iterations/iteration-19-pullzone-bugfixes.md Marks iter-19 completed and documents shipped changes/deferrals.
hoppy-knowledgebase/decision-log.md Documents lossy-enum strategy, password redaction approach, ArgGroup choice, and build provenance.
hoppy-knowledgebase/api/bunny-api-quirks.md Documents enum-growth behavior, storage-zone origin quirks, password redaction, DNS caveats.
fixtures/core/pullzone_get_magic_container.json Adds regression fixture for Magic-Container-backed pull zones (OriginType: 5).
crates/bunny-api-core/tests/storagezone_api.rs Updates tests to assert password round-trips at API-client layer.
crates/bunny-api-core/tests/pullzone_api.rs Adds tests for Magic Container OriginType and unknown OriginType fallback behavior.
crates/bunny-api-core/tests/dns_api.rs Updates DNS tests for record_type: Option<_>.
crates/bunny-api-core/src/types.rs Adds OriginType=5, changes request/response modeling (Option enums + storage passwords serialize).
crates/bunny-api-core/src/serde_helpers.rs New helper to lossy-deserialize unknown repr-enum integers into None.
crates/bunny-api-core/src/lib.rs Exposes serde_helpers module publicly.
build.rs New build script embedding short git SHA + “spec date” into --version long output.

Comment on lines 241 to 245
if let OutputFormat::Json = format {
let json = serde_json::to_string_pretty(sz).expect("failed to serialize to JSON");
let mut value = serde_json::to_value(sz).expect("failed to serialize StorageZone to JSON");
redact_secrets_in_json(&mut value, redact_cfg);
let json = serde_json::to_string_pretty(&value).expect("failed to serialize to JSON");
println!("{json}");
Comment thread src/redact.rs
let lower = name.to_lowercase();
// Allowlist: a few `_key` suffixes are not secrets in this codebase.
const KEY_SUFFIX_NOT_SECRET: &[&str] = &[
"zonesecuritykey", // PullZone — already gated separately
Comment thread build.rs
Comment on lines +15 to +16
let spec_date = newest_spec_mtime().unwrap_or_else(|| "unknown".to_owned());
println!("cargo:rustc-env=HOPPY_BUNNY_API_SPEC_DATE={spec_date}");
Comment thread build.rs
Comment on lines +20 to +22
println!("cargo:rerun-if-changed=specs");
}

- tests: tighten clap mutual-exclusion + required-arg stderr assertions
- tests: assert AccessKey header on volume-tier and update mocks
- tests: assert redaction placeholder shape (not just absence of secret)
- tests: set application/json content-type on unknown-OriginType mock
- tests: clarify comment on the MagicContainer regression test
- build.rs: skip unreadable spec entries instead of aborting newest_spec_mtime
- build.rs: only emit cargo:rerun-if-changed=.git/HEAD when the file exists
- redact.rs: doc comment now matches the null/string handling actually implemented

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ractive
ractive merged commit 935a4f1 into main May 7, 2026
5 of 8 checks passed
@ractive
ractive deleted the iter-19/pullzone-bugfixes branch May 7, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants