Skip to content

feat: add CLI with catalog pull command (fixes #4)#6

Open
jpower432 wants to merge 4 commits into
mainfrom
feat/catalog-pull-cli
Open

feat: add CLI with catalog pull command (fixes #4)#6
jpower432 wants to merge 4 commits into
mainfrom
feat/catalog-pull-cli

Conversation

@jpower432
Copy link
Copy Markdown
Member

@jpower432 jpower432 commented May 30, 2026

Summary

Adds complypack catalog pull CLI command to load Gemara control catalogs from OCI registries, addressing issue #4.

Changes

CLI Implementation:

  • Cobra-based CLI framework (cmd/complypack/)
  • catalog pull <reference> command for pulling Gemara catalogs
  • Docker credential chain authentication
  • Supports output to stdout or file (--output)
  • Plain HTTP support for local registries (--plain-http)

Registry Client:

  • internal/registry/ package for OCI operations
  • Reference parsing and repository creation
  • Docker credential resolution via ORAS

Dependencies:

  • Added github.com/spf13/cobra for CLI framework
  • Added github.com/gemaraproj/go-gemara for bundle unpacking
  • Bumped Go 1.23.0 → 1.25.0 (required by go-gemara)
  • Updated CI matrix to test with Go 1.25

Documentation:

  • README updated with CLI usage examples
  • Authentication guide using Docker credential chain

Example Usage

# Pull and output to stdout
complypack catalog pull ghcr.io/org/controls:v1.0

# Save to a file
complypack catalog pull ghcr.io/org/controls:v1.0 --output controls.yaml

# Pull from local registry
complypack catalog pull http://localhost:5000/controls:latest --plain-http

Testing

  • ✅ Unit tests for registry client and CLI structure
  • go build ./... passes
  • go test -race ./... passes
  • ✅ Overall test coverage: 61.4%

Related

Closes #4

jpower432 added 2 commits May 30, 2026 16:14
Add complypack CLI with `catalog pull` command to load Gemara control
catalogs from OCI registries.

Features:
- Cobra-based CLI framework
- OCI registry pull using ORAS v2
- Docker credential chain authentication
- Gemara bundle unpacking via go-gemara
- Output to stdout or file (--output)
- Plain HTTP support (--plain-http)

Changes:
- Bump Go 1.23.0 -> 1.25.0 (required by go-gemara)
- Add dependencies: spf13/cobra, gemaraproj/go-gemara
- Update CI test matrix to Go 1.25
- Add cmd/complypack CLI entrypoint
- Add internal/registry for OCI client helpers
- Update README with CLI usage documentation

Closes #4

Assisted-by: Claude (Anthropic, Claude 3.5 Sonnet 4.5)
Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
Refactor pkg/complypack tests to use testify/assert and testify/require
for cleaner, more readable test assertions.

Changes:
- Refactor pack_test.go to use assert/require
- Refactor config_test.go to use assert/require
- Replace verbose stdlib checks with testify helpers
  - if err != nil { t.Fatalf(...) } → require.NoError(t, err)
  - if got != want { t.Errorf(...) } → assert.Equal(t, want, got)
  - errors.Is checks → assert.ErrorIs(t, err, sentinel)

Benefits:
- Cleaner, more readable test code
- Consistent with complyctl and go-gemara
- Better failure messages
- Less boilerplate

Remaining test files (errors, mediatype, options, integration, unpack,
sign, verify) can be refactored incrementally following this pattern.

Assisted-by: Claude (Anthropic, Claude 3.5 Sonnet 4.5)
Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
@jpower432 jpower432 force-pushed the feat/catalog-pull-cli branch from 4e8a976 to 4797467 Compare May 30, 2026 20:14
jpower432 added 2 commits May 30, 2026 16:34
Resolve all HIGH and MEDIUM severity security findings from the
security audit:

**HIGH Findings:**

1. Output file path validation (catalog_pull.go:106)
   - Add validateOutputPath() to prevent path traversal
   - Reject absolute paths and ".." sequences
   - Check for symlinks to prevent write-through attacks
   - Use os.OpenFile with explicit 0o644 permissions (SC-005)
   - Implements SC-004 requirement for path validation

2. HTTP timeout (client.go:38)
   - Replace http.DefaultClient with custom client
   - Set 60-second timeout to prevent indefinite hangs
   - Improves resilience for CI/automation usage

**MEDIUM Findings:**

3. File close error handling (catalog_pull.go:110)
   - Explicitly check Close() error on output file
   - Catches write errors on buffered/networked filesystems
   - Prevents silent data corruption

4. Artifact size validation (catalog_pull.go:81)
   - Add validateArtifactSize() to check descriptor size
   - Enforce MaxContentSize limit (100MB) from library
   - Prevents memory exhaustion from malicious registries

**LOW Findings:**

5. Reference output sanitization (catalog_pull.go:79)
   - Use %q format verb instead of %s
   - Prevents ANSI escape sequence injection in terminal

**Tests:**

- Add TestValidateOutputPath for path validation logic
- Add TestValidateOutputPathSymlink for symlink detection
- Add TestValidateArtifactSize for size limit enforcement
- All tests pass with -race flag

Assisted-by: Claude (Anthropic, Claude 3.5 Sonnet 4.5)
Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
Resolve remaining security issues found in second Adversary review:

**HIGH Finding:**

1. Artifact size validation timing (catalog_pull.go:87-99)
   - Moved size check BEFORE oras.Copy to prevent downloading oversized artifacts
   - Use repo.Resolve() to fetch manifest descriptor first
   - Check manifest size against MaxContentSize before pulling content
   - Prevents memory exhaustion from actually occurring

**MEDIUM Findings:**

2. Output path sanitization (catalog_pull.go:133)
   - Changed format verb from %s to %q for output path
   - Consistent with reference sanitization on line 91
   - Prevents terminal control character injection

3. Go version mismatch (release.yml:29)
   - Updated release workflow from Go 1.23 to 1.25
   - Matches CI workflow and go.mod requirements
   - Prevents release pipeline breakage

**LOW Finding:**

4. HTTP timeout consistency (client.go:37-46)
   - Always set HTTP timeout regardless of credFunc value
   - Moved timeout setup outside credFunc conditional
   - Ensures resilience even without authentication

All tests pass with -race flag enabled.

Assisted-by: Claude (Anthropic, Claude 3.5 Sonnet 4.5)
Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
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.

As an user, I want to load Gemara control catalogs from an OCI registry so that I can use centrally published catalogs without copying files locally.

1 participant