Skip to content

Audit: medium & low severity findings (8) #553

Description

@BryanFRD

This issue tracks the medium and low severity findings from the full-codebase audit of FerrFlow. Critical and high findings are filed as individual issues. Each item below is independently fixable; check off as addressed.

Medium

  • [docs/CLI] JSON Schema rejects the snake_case keys used in the README's own examples
    - schema/ferrflow.json:148
    - The schema sets additionalProperties: false and declares package fields only in camelCase (versionedFiles, sharedPaths, dependsOn, tagTemplate). The Rust config accepts BOTH forms via serde aliases (package.rs uses serde name versioned_files with alias="versionedFiles", etc.), and the README JSON/JSON5 examples (README.md:156, 215, 241) use the snake_case forms versioned_files and …
    - Fix: Either add the snake_case aliases to the schema properties (and relax additionalProperties), or standardize the README examples and the serde model on one casing and document the other as a deprecated alias.
  • [ux/CLI] Error message tells users to run ferrflow release --recover, a flag that does not exist
    - src/git/push.rs:373-378
    - When HEAD is detached during a non-fast-forward rebase recovery, the error reads: 'Refusing to rebase: HEAD is detached. ... (To recover an in-progress release, use ferrflow release --recover or reset the branch manually.)'. The CLI (src/cli.rs Commands::Release) defines only --force, --force-version, --channel, --draft, --force-unlock; there is no --recover flag (grep confirms the s…
    - Fix: Remove the --recover reference or implement the flag. The real recovery levers are --force-unlock and manual git reset; point at those.
  • [bug/CLI] Changelog breaking-change classification uses naive substring matching, mis-bucketing entries
    - src/changelog.rs:103-114
    - build_section classifies each commit with commit.message.contains("BREAKING CHANGE") (anywhere in the message, no line-start, no colon) and first_line.contains("!:"). This diverges from determine_bump and produces wrong changelog sections: (1) any commit whose body mentions the words 'BREAKING CHANGE' in prose is listed under '### Breaking Changes'; (2) first_line.contains("!:") flags a su…
    - Fix: Reuse determine_bump / the same regexes used for version detection to classify commits, instead of ad-hoc contains/starts_with on a lowercased first line.

Low

  • [bug/CLI] bump_zerover does not clear pre-release/build metadata before bumping
    - src/versioning/strategies.rs:76-98
    - bump_semver explicitly resets v.pre = Prerelease::EMPTY and v.build = BuildMetadata::EMPTY before incrementing, but bump_zerover does not. If a zerover-strategy package's current version carries a pre-release or build segment (e.g. 0.4.0-beta.1+build), the bumped output retains that metadata (0.5.0-beta.1+build), producing a non-clean stable version. Same idempotency/cleanliness contra…
    - Fix: Clear v.pre and v.build at the top of bump_zerover as bump_semver does, and add a test covering a zerover bump from a pre-release input.
  • [security/CLI] Config-driven file paths are joined without repo-root containment check (path traversal in bot/PR context)
    - src/formats/mod.rs:64-74
    - read_version/write_version do repo_root.join(&vf.path) with no normalization or containment check; the same pattern applies to the changelog path (src/changelog.rs:69-82 root.join(rel)). A versioned_files[].path (or changelog) of ../../etc/something or an absolute path escapes the repository and lets FerrFlow write outside the working tree. For a developer running locally on their ow…
    - Fix: Canonicalize the joined path and assert it stays within repo_root (reject absolute paths and .. escapes) before any read/write, at minimum when running under bot/Action mode.
  • [security/CLI] Remote-validation --ref and config paths are interpolated into API URLs without encoding
    - src/validate/source.rs:72-83
    - GitHubSource::read_file builds .../contents/{path}?ref={r} and GitLabSource builds a URL with ?ref={r}, interpolating the user-supplied --ref value and the config path directly without URL-encoding (the GitLab path is percent-encoded, but the ref is not, and the GitHub path is not). A ref or path containing ?, &, #, or spaces will silently break the request or smuggle extra query par…
    - Fix: Percent-encode the git_ref and the path segments before interpolation (the GitLab source already does it for the project id and path — apply the same to the ref and to the GitHub source).
  • [security/CLI] Forge API base host is taken verbatim from the git remote with no scheme/host validation
    - src/forge/mod.rs:142-175
    - build_forge constructs https://{host}/api/v3 (GitHub) or https://{host}/api/v4 (GitLab) from host extracted out of the repo's remote URL (extract_host), then sends the bearer token to that host. extract_host correctly strips userinfo so a evil@github.com-style URL can't masquerade, and the host comes from the local repo's own remote (trusted), so this is not a live SSRF. It is, however, …
    - Fix: Optionally validate that the derived host is a syntactically valid hostname (no path/port-injection, no embedded credentials) before building the api_base and attaching the token, and document that a self-hosted forge host receives the token.
  • [ux/CLI] GitLab forge silently degrades draft and draft-publish semantics versus GitHub
    - src/forge/gitlab.rs:29-65
    - On GitLab, --draft only prints a warning and creates a published release (create_release ignores draft after warning), find_draft_release always returns Ok(None), and publish_release is a no-op. So the documented draft workflow ('Create releases as drafts ... a subsequent ferrflow release without --draft will detect and publish existing drafts automatically', cli.rs:57-58) silently does …
    - Fix: Document the GitLab draft limitation in the README/CLI help, and consider erroring (not just warning) when --draft is combined with a GitLab remote so the user isn't surprised by an immediately-public release.

Found during a full-codebase audit of the FerrLabs workspace.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions