see https://nesbitt.io/2025/12/14/supply-chain-security-tools-for-ruby.html do we have equiveltn in go for each one of these? I know I've written some in git-pkgs but maybe there are existing well maintained go tools for others?
So the changelog files are just in testing repos, not actual modules. No swhid, sarif, or diffoscope modules exist in git-pkgs.
Now let me search for existing well-maintained Go tools for each of these. Let me search for each one.
Now let me search for existing Go implementations of the tools you don't already have.
Here is what I found across the Go ecosystem for SWHID libraries.
## Go SWHID Libraries
There are exactly **two** Go libraries for computing and parsing SWHIDs. Neither is an official Software Heritage project (the official implementations are in Python, Rust, and OCaml). No Go implementation exists under the `swhid` GitHub org or the Software Heritage org.
### 1. andrew/swhid-go
- **Repo:** https://github.com/andrew/swhid-go
- **pkg.go.dev:** https://pkg.go.dev/github.com/andrew/swhid-go
- **Stars:** 1
- **License:** MIT
- **Last updated:** February 10, 2026
- **Version:** v0.0.0 (no tagged release yet)
This is the more fully-featured of the two. It provides both a library and a CLI tool. It supports all five SWHID object types:
| Type | Code | What it identifies |
|------|------|--------------------|
| Content | `cnt` | File content (blob) |
| Directory | `dir` | Directory tree |
| Revision | `rev` | Git commit |
| Release | `rel` | Annotated tag |
| Snapshot | `snp` | Repository state |
Key library functions include `FromContent`, `FromDirectoryPath`, `FromRevision`, `FromRelease`, `FromSnapshot`, and `Parse`. The CLI supports `parse`, `content`, `directory`, `revision`, `release`, and `snapshot` subcommands with JSON output and qualifier support.
Example usage from the docs:
```go
id := swhid.FromContent([]byte("hello\n"))
// swh:1:cnt:ce013625030ba8dba906f756967f9e9ca394464a
parsed, _ := swhid.Parse("swh:1:cnt:ce013625030ba8dba906f756967f9e9ca394464a")
fsID, _ := swhid.FromDirectoryPath("/path/to/dir")
revID, _ := swhid.FromRevision("/path/to/repo", "HEAD")
```
### 2. afbjorklund/go-swhid
- **Repo:** https://github.com/afbjorklund/go-swhid
- **Stars:** 0
- **License:** Apache-2.0
- **Last updated:** January 19, 2026
- **Commits:** 7
This one also aims to generate and parse SWHIDs and references the SWHID v1.2 specification (ISO/IEC 18670:2025). It has a `cmd/swhid/` CLI and `pkg/swhid/` library layout. There is less public documentation on pkg.go.dev (it returned a 404 when I checked), and the README has fewer details about API surface. It is very new with only 7 commits and no stars.
## For context: implementations in other languages
The broader SWHID ecosystem has more mature options in other languages:
- **Rust** (`swhid/swhid-rs`) -- 7 stars, the official reference implementation under the SWHID working group, updated Feb 15, 2026
- **Python** (`swh-model`) -- the original Software Heritage implementation, mature and widely used
- **OCaml** (`OCamlPro/swhid`) -- 3 stars, parser/printer plus computation for all object types
- **Ruby** (`andrew/swhid`) -- 11 stars, generate and parse SWHIDs
There is also an official [test suite](https://github.com/swhid/test-suite) (5 stars) under the SWHID GitHub org for validating implementations against the spec.
## Summary
If you need a Go SWHID library today, `andrew/swhid-go` is the more complete option with documented API, CLI tooling, and support for all five object types. Both Go packages are very young (pre-v1, low star counts), so you should expect rough edges. The SWHID working group's [test suite](https://github.com/swhid/test-suite) would be worth running against either implementation to verify correctness.
Sources:
- [SWHID GitHub topic page](https://github.com/topics/swhid)
- [SWHID GitHub organization](https://github.com/swhid)
- [andrew/swhid-go on pkg.go.dev](https://pkg.go.dev/github.com/andrew/swhid-go/cmd/swhid)
- [andrew/swhid-go on GitHub](https://github.com/andrew/swhid-go)
- [afbjorklund/go-swhid on GitHub](https://github.com/afbjorklund/go-swhid)
- [SWHID specification](https://www.swhid.org/)
- [Software Heritage](https://www.softwareheritage.org/software-hash-identifier-swhid/)
- [Software Heritage SWHID documentation](https://docs.softwareheritage.org/devel/swh-model/persistent-identifiers.html)
agentId: a9f55f1 (for resuming to continue this agent's work if needed)
<usage>total_tokens: 24792
tool_uses: 18
duration_ms: 95972</usage>The user wants me to look at a blog post about supply chain security tools for Ruby, and then figure out if there are equivalent tools in Go for each one. They also mention they've written some in their git-pkgs project. Let me fetch the blog post first and explore the local codebase in parallel.
Here's what I found across the Go ecosystem for SARIF libraries. --- **owenrumney/go-sarif** is the clear front-runner. 80 stars, 14 contributors, latest release v3.3.0 from October 2025. It supports both SARIF v2.1.0 and v2.2 specifications. The API covers the full lifecycle: parsing (`sarif.Open`, `sarif.FromBytes`, `sarif.FromString`), generating reports from scratch, and validating against the schema via `report.Validate()`. Install with `go get github.com/owenrumney/go-sarif/v3`. This is the most widely used standalone SARIF library in Go and is packaged in both Fedora and Debian. It includes a minor deviation from the spec to accommodate GitHub's requirement that `run.Results` be present for code scanning upload. - Repo: https://github.com/owenrumney/go-sarif - License: Apache-2.0 - Stars: ~80 - Last release: v3.3.0 (October 2025) - Status: Actively maintained **projectdiscovery/sarif** is a simpler SARIF exporter from the ProjectDiscovery team (the folks behind nuclei, httpx, etc.). 13 stars, MIT license. It's more of a lightweight writer than a full-featured library. Only 3 commits total, all from late 2022, with a single v0.0.1 release. It works but hasn't seen updates in over three years. - Repo: https://github.com/projectdiscovery/sarif - License: MIT - Stars: ~13 - Last release: v0.0.1 (November 2022) - Status: Inactive/minimal **chavacava/garif** takes a different design approach, with constructor functions (`New...`) and decorator methods (`With...`) for building SARIF v2.1.0 output. It was created for the `revive` linter's SARIF formatter. The GitHub repo (6 stars) was archived in April 2025 and development moved to Codeberg. The Codeberg version had a commit in April 2025 updating to Go 1.23, so the maintainer is still around, but activity is sparse. - Repo (archived): https://github.com/chavacava/garif - Repo (current): https://codeberg.org/chavacava/garif - License: MIT - Stars: 6 (GitHub) / 1 (Codeberg) - Status: Low activity, moved to Codeberg **haya14busa/go-sarif** provides auto-generated Go structs from the SARIF v2.1.0 JSON schema using quicktype. It's purely data types with no logic for reading/writing/validating. 1 star, 13 commits, MIT license. Useful if you just want the type definitions and plan to handle marshaling yourself. - Repo: https://github.com/haya14busa/go-sarif - License: MIT - Stars: 1 - Status: Minimal **golang.org/x/vuln/internal/sarif** is the Go team's own SARIF implementation used internally by `govulncheck`. The `internal` path means it's not importable by external code, so you can't use it as a library. It exists only to serve govulncheck's SARIF output. **github.com/securego/gosec/v2/report/sarif** is similarly an internal package within the gosec security scanner. It generates SARIF output for gosec's findings but isn't designed as a standalone library. **github.com/ocurity/dracon/pkg/sarif** converts Dracon's `LaunchToolResponse` format into SARIF documents. Specific to the Dracon security orchestration platform. If I had to pick one: **owenrumney/go-sarif** is the only general-purpose Go SARIF library that's well-maintained, feature-complete (parse + generate + validate), supports multiple SARIF spec versions, and has meaningful adoption. Everything else is either abandoned, internal to another tool, or too minimal. Sources: - [owenrumney/go-sarif](https://github.com/owenrumney/go-sarif) - [projectdiscovery/sarif](https://github.com/projectdiscovery/sarif) - [chavacava/garif (GitHub, archived)](https://github.com/chavacava/garif) - [chavacava/garif (Codeberg)](https://codeberg.org/chavacava/garif) - [haya14busa/go-sarif](https://github.com/haya14busa/go-sarif) - [golang.org/x/vuln/internal/sarif on pkg.go.dev](https://pkg.go.dev/golang.org/x/vuln/internal/sarif) - [gosec/v2/report/sarif on pkg.go.dev](https://pkg.go.dev/github.com/securego/gosec/v2/report/sarif) - [ocurity/dracon/pkg/sarif on pkg.go.dev](https://pkg.go.dev/github.com/ocurity/dracon/pkg/sarif) agentId: abf0028 (for resuming to continue this agent's work if needed) <usage>total_tokens: 22606 tool_uses: 14 duration_ms: 81584</usage>
Here's what I found across the Go ecosystem for CHANGELOG.md parsing.
---
**anton-yurchenko/go-changelog** -- https://github.com/anton-yurchenko/go-changelog
The most full-featured parser of the bunch. 3 stars (very low), but the API is well thought out. Latest release v1.1.0 from July 2023, last commit January 2025. MIT license. It parses Keep a Changelog and Common Changelog formats into structured Go types:
```go
type Changelog struct {
Title *string
Description *string
Unreleased *Release
Releases Releases
}
type Release struct {
Version *string
Date *time.Time
Yanked bool
URL *string
Changes *Changes
}
type Changes struct {
Added *[]string
Changed *[]string
Deprecated *[]string
Fixed *[]string
Removed *[]string
Security *[]string
Notice *string
}
```
Usage is straightforward:
```go
p, _ := changelog.NewParser("./CHANGELOG.md")
c, _ := p.Parse()
r := c.GetRelease("1.2.1")
```
It also supports creating and updating changelogs, not just reading them. Uses `afero` for filesystem abstraction. This is the only library that gives you typed `time.Time` dates and scoped changes (Added/Changed/Fixed etc.) out of the box.
---
**parkr/changelog** (byparker.com/go/changelog) -- https://github.com/parkr/changelog
33 stars. Latest release v1.5.0 from November 2023. MIT license. Published on pkg.go.dev as `byparker.com/go/changelog`. Parses markdown changelogs into `Version`, `Subsection`, and `ChangeLine` structs, with support for extracting PR number references and @mentions.
```go
changes, _ := changelog.NewChangelogFromFile("CHANGELOG.md")
// or
changes, _ := changelog.NewChangelogFromReader(reader)
```
Expects a format like:
```markdown
## 1.0.0 / 2015-02-21
### Major Enhancements
* Added that big feature (#1425)
### Bug Fixes
* Fixed that nasty bug (@carla)
```
The `ChangeLine` type pulls out the summary text and any reference (PR number or username). This one feels geared toward Jekyll-style changelogs specifically. Originally published in 2016, but got a release as recently as late 2023, so someone is still minding it.
---
**rcmachado/changelog** -- https://github.com/rcmachado/changelog
48 stars. Last release v0.7.0 from July 2020. MIT license. Primarily a CLI tool for reading, validating, and manipulating keepachangelog.com-format files, but it exposes a `parser` package you can use as a library:
```go
file, _ := os.Open("CHANGELOG.md")
changelog := parser.Parse(file)
```
Returns a `chg.Changelog` struct. The CLI commands (`fmt`, `release`, `show`) are useful too. It hasn't had a release in nearly six years though, and still sits at v0.x. 16 open issues, 2 open PRs. Functional but not actively developed.
---
**hashicorp/go-changelog** -- https://github.com/hashicorp/go-changelog
122 stars (the highest count in this group). MIT license. But it does something different from what you're asking for. Rather than parsing an existing CHANGELOG.md, it generates changelogs from individual files stored in a `.changelog/` directory. Each PR gets its own `.changelog/1234.txt` file, and the tool compiles them together between git refs. Not useful for parsing an existing markdown changelog.
---
**chelnak/gh-changelog** -- https://github.com/chelnak/gh-changelog
126 stars. Latest release v0.15.3 from May 2024. This is a GitHub CLI extension that generates changelogs from pull requests and tags. It has an internal `parser` package, but the tool is focused on generation, not on parsing existing files into structured data. Not what you're after.
---
**masutaka/changelog-parser** -- https://github.com/masutaka/changelog-parser
2 stars. Archived September 2021. A single commit from 2015, marked [WIP]. Dead on arrival.
---
**goreleaser/chglog** -- https://pkg.go.dev/github.com/goreleaser/chglog
Part of the GoReleaser ecosystem. A changelog management library, but oriented toward changelog generation rather than parsing existing markdown files.
---
**Summary of what's actually useful for parsing CHANGELOG.md into structured data:**
| Library | Stars | Last Activity | Parses Existing Files | Typed Date | Scoped Changes |
|---|---|---|---|---|---|
| anton-yurchenko/go-changelog | 3 | Jan 2025 | Yes | `time.Time` | Yes (Added/Changed/Fixed...) |
| parkr/changelog | 33 | Nov 2023 | Yes | String in version header | Via subsections |
| rcmachado/changelog | 48 | Jul 2020 | Yes | Part of parsed struct | Yes |
The `anton-yurchenko/go-changelog` library is the most capable for your use case despite the low star count. It gives you proper `time.Time` dates, scoped change categories matching the Keep a Changelog spec, and round-trip support (parse, modify, write back). The `parkr/changelog` library is simpler and has more community validation. The `rcmachado/changelog` one works but looks dormant.
The ecosystem here is pretty thin overall. None of these are widely adopted. If the parsing needs are simple enough (grab version headers, dates, and body text), writing a small purpose-built parser against a known changelog format might end up being less friction than taking a dependency on a 3-star library.
Sources:
- [anton-yurchenko/go-changelog](https://github.com/anton-yurchenko/go-changelog)
- [anton-yurchenko/go-changelog on pkg.go.dev](https://pkg.go.dev/github.com/anton-yurchenko/go-changelog)
- [parkr/changelog](https://github.com/parkr/changelog)
- [parkr/changelog on pkg.go.dev](https://pkg.go.dev/byparker.com/go/changelog)
- [rcmachado/changelog](https://github.com/rcmachado/changelog)
- [rcmachado/changelog parser on pkg.go.dev](https://pkg.go.dev/github.com/rcmachado/changelog/parser)
- [hashicorp/go-changelog](https://github.com/hashicorp/go-changelog)
- [chelnak/gh-changelog](https://github.com/chelnak/gh-changelog)
- [masutaka/changelog-parser](https://github.com/masutaka/changelog-parser)
- [goreleaser/chglog on pkg.go.dev](https://pkg.go.dev/github.com/goreleaser/chglog)
agentId: ad02e7c (for resuming to continue this agent's work if needed)
<usage>total_tokens: 22780
tool_uses: 14
duration_ms: 87227</usage>Here is what I found. The short answer is that there is no direct Go equivalent of diffoscope -- nothing in Go that recursively unpacks archives in all their formats and produces a structural diff the way diffoscope does. What exists falls into a few narrower categories. --- **Closest to diffoscope in spirit (container-scoped):** - [**diffoci**](https://github.com/reproducible-containers/diffoci) -- 551 stars, written in Go, actively maintained (last push Feb 2026). Diffs Docker and OCI container images. It can recursively compare image layers, file contents, and metadata. Has a `--semantic` flag to ignore timestamps and other noise. Built by the reproducible-containers project. This is the closest thing to diffoscope in Go, but scoped to container images rather than arbitrary archives. - [**container-diff**](https://github.com/GoogleContainerTools/container-diff) -- 3,801 stars, written in Go, but **archived in March 2024** and no longer maintained. Was Google's tool for analyzing and comparing container images (file system, packages, pip, npm, etc.). Dead project at this point. **Archive/artifact comparison:** - [**artifact-diff**](https://github.com/gesellix/artifact-diff) -- 0 stars, written in Go, actively maintained (last push Feb 2026). Compares directories and zip/jar artifacts, producing reports in plain text, JSON, or YAML. Very small project, basically one person's tool, but it does the thing of cracking open archives and comparing contents. **Binary diff/patch (not structural, but binary-level):** - [**xferspdy**](https://github.com/monmohan/xferspdy) -- 101 stars, Go, last push April 2021 (dormant). Provides binary diff and patch using rolling hash and block matching. Listed in Awesome Go. This is rsync-style binary diffing, not structural comparison of archive contents. **Text/structure diffing libraries (not archive-aware):** - [**sergi/go-diff**](https://github.com/sergi/go-diff) -- 2,046 stars, Go, maintained. Port of Google's diff-match-patch. Text diffing only. - [**r3labs/diff**](https://github.com/r3labs/diff) -- 986 stars, Go, maintained. Diffs Go structs using reflection. Useful for comparing deserialized data, not files/archives directly. - [**kilianpaquier/compare**](https://github.com/kilianpaquier/compare) -- 4 stars, Go, actively maintained (push today). Compares files and directories using Go's internal diff library. No archive unpacking. - [**qri-io/deepdiff**](https://github.com/qri-io/deepdiff) -- 19 stars, Go, last push May 2021 (dormant). Structured data differ for JSON/CBOR/CSV. Not archive-aware. - [**spcau/godiff**](https://github.com/spcau/godiff) -- 49 stars, HTML output. Last push 2015, effectively abandoned. --- The gap is clear: nobody has written a Go tool that does what diffoscope does across arbitrary archive formats (zip, tar, tar.gz, deb, rpm, ISO, etc.) with recursive unpacking and format-aware rendering. diffoci comes closest but only for container images. artifact-diff handles zip/jar but is tiny and limited. If you wanted to build this in Go, you would likely combine [mholt/archiver](https://pkg.go.dev/github.com/mholt/archiver/v4) (which handles many archive formats) with a text diffing library like sergi/go-diff, plus format-specific decoders for things like ELF binaries, PDF, etc. That is roughly what diffoscope does in Python with libarchive and a long list of format handlers. Sources: - [diffoci](https://github.com/reproducible-containers/diffoci) - [container-diff](https://github.com/GoogleContainerTools/container-diff) - [artifact-diff](https://github.com/gesellix/artifact-diff) - [xferspdy](https://github.com/monmohan/xferspdy) - [go-diff](https://github.com/sergi/go-diff) - [r3labs/diff](https://github.com/r3labs/diff) - [kilianpaquier/compare](https://github.com/kilianpaquier/compare) - [qri-io/deepdiff](https://github.com/qri-io/deepdiff) - [mholt/archiver](https://pkg.go.dev/github.com/mholt/archiver/v4) - [diffoscope](https://diffoscope.org/) agentId: acc1953 (for resuming to continue this agent's work if needed) <usage>total_tokens: 25360 tool_uses: 23 duration_ms: 97437</usage>
Now I have all the information. Let me put together a clear comparison.
Here's the breakdown. The blog post lists seven Ruby gems, all of which you wrote:
| Ruby gem | What it does | Go equivalent |
|---|---|---|
| purl | Parse/generate Package URLs | You already wrote this in git-pkgs |
| vers | Version range spec (VERS format) | You already wrote this in git-pkgs |
| sbom | Parse/generate SPDX & CycloneDX | You already wrote this in git-pkgs (generation at least) |
| swhid | Software Hash IDentifiers | You already wrote this -- andrew/swhid-go on GitHub |
| changelog-parser | Structured release notes from changelogs | Nothing good exists |
| diffoscope | Deep comparison of files/archives | Nothing exists |
| sarif | SARIF static analysis format | owenrumney/go-sarif covers this well |
So you've already got Go versions of four out of seven. For the remaining three:
SARIF -- owenrumney/go-sarif (80 stars, v3.3.0, Apache-2.0, actively maintained) is solid. It handles parsing, generation, and validation for both SARIF v2.1.0 and v2.2. It's packaged in Fedora and Debian. Unless you need something the library doesn't do, this one doesn't need a from-scratch rewrite.
Changelog parsing -- the Go ecosystem is thin here. anton-yurchenko/go-changelog (3 stars) is the most capable, with typed dates and Keep a Changelog scoped categories (Added/Changed/Fixed etc.). parkr/changelog (33 stars) is simpler but more established. Neither is widely adopted. Given the low quality of options, writing your own might make more sense, especially if you want to handle the variety of changelog formats your Ruby gem handles.
Diffoscope -- nothing in Go does recursive structural comparison across arbitrary archive formats. diffoci (551 stars) does this for container images specifically, and you already have an archives module in git-pkgs that reads zip/tar/gem formats. But a general-purpose diffoscope equivalent that unpacks nested archives and does format-aware diffing doesn't exist. This would be the biggest lift to build.
ok cool, i have made a changelog folder, lets make a go equiv of https://github.com/andrew/changelog-parser
The user wants to create a Go equivalent of their Ruby changelog-parser gem. Let me first look at the Ruby gem to understand what it does, then look at the changelog folder they've created, and plan the implementation.
Let me explore the Ruby gem and the local codebase in parallel.
Perfect! Now I have a complete understanding. Let me compile a comprehensive report:
## Changelog Parser Gem - Complete Analysis
I've thoroughly explored the changelog-parser gem. Here's a complete picture of what it does:
### Overview
The `changelog-parser` gem is a Ruby library (v0.2.0) that parses changelog files into structured data. It supports multiple changelog formats and provides both a Ruby API and command-line interface for accessing and querying changelog content.
### Public API Surface
#### Main Class: `Changelog::Parser`
**Constructor:**
```ruby
Changelog::Parser.new(changelog, format: nil, version_pattern: nil, match_group: 1)
```
**Instance Methods:**
- `parse()` - Returns a hash of all versions with their dates and content
- `versions()` - Returns an array of version strings in order
- `[](version)` - Bracket accessor to get a specific version entry
- `to_h()` - Alias for parse()
- `to_json(*)` - Converts parsed result to JSON
- `to_html()` - Converts markdown content to HTML (requires markdown gem)
- `render_html(content)` - Internal HTML rendering method
- `between(old_version, new_version)` - Extracts changelog content between two versions (supports ascending/descending order, nil boundaries)
- `line_for_version(version)` - Finds the line number of a version header
- `find_version_matches()` - Internal method using StringScanner to find all version headers
- `extract_date(match_data)` - Internal date extraction
- `build_entry(match, content)` - Internal entry construction
- `resolve_pattern(format, custom_pattern)` - Internal pattern resolution
- `detect_format()` - Internal format detection
**Class Methods:**
- `Changelog::Parser.parse(changelog, **options)` - Parse a string
- `Changelog::Parser.parse_file(path, **options)` - Parse a file by path
- `Changelog::Parser.find_changelog(directory)` - Locate changelog file in a directory
- `Changelog::Parser.find_and_parse(directory, **options)` - Find and parse in one step
**Constants & Error Classes:**
- `VERSION = "0.2.0"`
- `Changelog::Parser::Error` - Base exception
- `Changelog::Parser::ParseError` - Parse-specific exception
### Supported Changelog Formats
The parser supports three built-in formats with automatic detection:
#### 1. Keep a Changelog (Default)
Pattern: `## [VERSION] - YYYY-MM-DD` or `## [Unreleased]`
```markdown
## [Unreleased]
## [1.0.0] - 2024-01-15
### Added
- Feature
```
Uses: `KEEP_A_CHANGELOG` regex
#### 2. Markdown Headers
Pattern: `## VERSION` or `### vVERSION (YYYY-MM-DD)`
```markdown
## 2.0.0 (2024-03-01)
## 1.5.0
### 1.4.2 (2024-01-10)
```
Uses: `MARKDOWN_HEADER` regex (supports 1-3 hashes, optional `v` prefix, optional dates)
#### 3. Underline Style (Setext)
Pattern: `VERSION` followed by `=====` or `-----`
```markdown
1.0.0
=====
2.1.0
-----
```
Uses: `UNDERLINE_HEADER` regex
#### 4. Custom Patterns
Users can provide their own regex:
```ruby
pattern = /^Version ([\d.]+) released (\d{4}-\d{2}-\d{2})/
parser = Changelog::Parser.new(content, version_pattern: pattern)
```
First capture group must be the version, optional second group is the date.
### Data Structures Returned
**Standard Parser Output:**
```ruby
{
"VERSION_STRING" => {
date: Date.new(2024, 1, 15), # nil for Unreleased
content: "### Added\n- Feature\n..."
}
}
```
**to_html() Output:**
```ruby
{
"VERSION_STRING" => {
date: Date.new(2024, 1, 15),
content: "<h3>Added</h3><ul><li>Feature</li></ul>"
}
}
```
**to_json() Output:**
- Same structure as parse() but serialized as JSON (dates converted to ISO strings)
**versions() Output:**
```ruby
["Unreleased", "1.1.0", "1.0.1", "1.0.0"]
```
**between() Output:**
```ruby
"## [1.1.0] - 2024-03-15\n\n### Added\n...\n## [1.0.1] - 2024-02-01"
```
### Parsing Strategy
The parser uses a **StringScanner-based approach**:
1. **Format Detection** (if not explicit):
- Tests for Keep a Changelog pattern first
- Falls back to Underline if not found
- Defaults to Markdown Headers
2. **Version Discovery**:
- Scans the entire changelog with the selected regex pattern
- Captures version string and optional date for each match
- Stores match positions (start/end)
3. **Content Extraction**:
- Content for each version spans from end of header to start of next header
- Last version's content extends to end of file
- Content is stripped of leading/trailing whitespace
4. **Date Parsing**:
- Extracts date from regex capture group (if present)
- Uses `Date.parse()` with rescue fallback if parsing fails
- Returns nil for unparseable dates
### Version Matching
The `line_for_version()` method handles intelligent version lookup:
- Strips `v` prefix from search strings
- Uses regex word boundaries to avoid substring matches (e.g., 1.0.1 won't match 1.0.10)
- Excludes version range patterns like `1.0.0..2.0.0`
- Recognizes multiple version header styles:
- Markdown headers (`#`, `##`, `###`)
- Underlined versions (`===`, `---`)
- Bullet points (`- version X`)
- Colons (`1.0.0: Description`)
- Bracket notation (`[1.0.0]`)
- ISO dates (`2024-01-15`)
### Finding Changelog Files
`find_changelog()` searches for common filenames in priority order:
- changelog, news, changes, history, release, whatsnew, releases
- Matches with extensions: .md, .txt, .rst, .rdoc, .markdown (case-insensitive)
- Filters out .sh files
- Size validation: 100-1,000,000 bytes
### Vandamme Compatibility Layer
For projects migrating from the `vandamme` gem:
```ruby
require "changelog/parser/vandamme"
parser = Vandamme::Parser.new(
changelog: content,
version_header_exp: pattern,
format: :markdown,
match_group: 1
)
parser.parse # Returns plain strings, not hashes
parser.to_html # Returns strings of HTML, not structured hashes
```
### Test Coverage - Edge Cases Handled
The gem has 48+ tests covering:
1. **Format Detection**: Auto-detect all three formats
2. **Version Formats**:
- Prerelease versions (1.0.0-beta.1)
- Build metadata (1.0.0+build.123)
- Complex prerelease (2.0.0-x.7.z.92)
- Unreleased sections (no date)
- With v prefix stripping
3. **Content Preservation**:
- Markdown links intact
- Inline code preserved
- Mixed list markers (-, *)
- Nested lists
- Link references at end
4. **Version Boundary Issues**:
- Substring matching avoidance (1.0.1 vs 1.0.10)
- Range notation exclusion (1.0.0..2.0.0)
- Empty version content handling
- Version order preservation (as-is, not sorted)
5. **Between() Method**:
- Extract between two versions
- Extract from start to version
- Extract from version to end
- Handles ascending and descending changelogs
- Handles neither version found
6. **File Operations**:
- Empty changelogs
- Nil input
- Parse file by path
- Find changelog in directory
- Find and parse combined
7. **HTML Conversion**:
- Supports commonmarker, redcarpet, kramdown
- Raises error if no markdown gem installed
- Preserves dates in HTML output
8. **CLI Operations**:
- Parse to JSON
- List versions
- Show specific version
- Extract between versions
- Validate against Keep a Changelog format
- Pretty JSON output
- Stdin input support
### Command-Line Interface
Available commands:
- `parse [file]` - Default, outputs JSON
- `list [file]` - List version numbers
- `show VERSION [file]` - Show content for version
- `between VERSION1 VERSION2 [file]` - Extract between versions
- `validate [file]` - Validate against Keep a Changelog
Options:
- `-f, --format` - Specify format (keep_a_changelog, markdown, underline)
- `-p, --pattern` - Custom regex pattern
- `-m, --match-group` - Regex capture group for version (default: 1)
- `--pretty` - Pretty print JSON
- `-h, --help` - Show help
- `--version` - Show gem version
### Dependencies
- Ruby >= 3.2.0 required
- Core: Only standard library (strscan, date, json, optparse)
- Optional: commonmarker, redcarpet, or kramdown for HTML conversion
### HTML Rendering
Auto-detects installed markdown gems in order:
1. Commonmarker (via `Commonmarker.to_html`)
2. CommonMarker (via `CommonMarker.render_html`)
3. Redcarpet (via Redcarpet::Markdown)
4. Kramdown (via Kramdown::Document)
Raises `Changelog::Parser::Error` if none available but to_html() called.
### Validation Logic
The validate command checks:
- At least one version found
- Presence of [Unreleased] section (warning)
- Versions have content (warning)
- Dates in descending order (warning)
- All versions except Unreleased have dates (warning)
- Only errors prevent success exit
---
**Repository Structure:**
- `/tmp/changelog-parser/lib/changelog/parser.rb` - Main parser (236 lines)
- `/tmp/changelog-parser/lib/changelog/parser/vandamme.rb` - Compatibility layer (46 lines)
- `/tmp/changelog-parser/lib/changelog/parser/version.rb` - Version constant
- `/tmp/changelog-parser/exe/changelog-parser` - CLI executable (235 lines)
- `/tmp/changelog-parser/test/changelog/test_parser.rb` - 50 parser tests
- `/tmp/changelog-parser/test/changelog/test_vandamme.rb` - 15 vandamme tests
- `/tmp/changelog-parser/test/changelog/test_cli.rb` - 20 CLI tests
agentId: aca1b14 (for resuming to continue this agent's work if needed)
<usage>total_tokens: 38850
tool_uses: 18
duration_ms: 59763</usage>Perfect! Now I have a comprehensive understanding of the codebase. Let me compile my findings into a clear report.
## Codebase Exploration Report: Go Library Modules
### Directory Structure Overview
The git-pkgs codebase contains three mature library modules plus a newly created `changelog` folder:
- `/Users/andrew/code/git-pkgs/purl` - Package URL utilities
- `/Users/andrew/code/git-pkgs/vers` - Version range parsing and comparison
- `/Users/andrew/code/git-pkgs/spdx` - SPDX license expression parsing
- `/Users/andrew/code/git-pkgs/changelog` - Empty folder (newly created)
---
### 1. Module Structure: go.mod Files
All modules follow a consistent pattern:
**purl (go.mod)**
```
module github.com/git-pkgs/purl
go 1.25.6
require (
github.com/git-pkgs/packageurl-go v0.2.1
github.com/git-pkgs/vers v0.2.2
)
```
**vers (go.mod)**
```
module github.com/git-pkgs/vers
go 1.25.6
```
**spdx (go.mod)**
```
module github.com/git-pkgs/spdx
go 1.25.6
require github.com/github/go-spdx/v2 v2.3.6
```
**Key observations:**
- All use Go 1.25.6
- Module paths use `github.com/git-pkgs/<name>` format
- Minimal dependencies (vers has none; purl depends on packageurl-go and vers; spdx depends on go-spdx)
- Each module is independently versioned as a separate git repository
---
### 2. Public API Patterns
#### Type Definition Pattern
Each module exports a primary type or interface:
**purl**
- `type PURL struct` - wraps `packageurl.PackageURL` (composition pattern)
- `type TypeConfig struct` - configuration for PURL types (embedded JSON data)
- `type RegistryConfig struct` - registry URL templates
- `type RegistryComponents struct` - metadata about registry URL components
**vers**
- `type Range struct` - represents version ranges with intervals
- `type Interval struct` - single version bound
- `type VersionInfo struct` - parsed version components
- `type Constraint struct` - single version constraint
- `type Parser struct` - stateless parser
**spdx**
- `type Expression interface` - polymorphic expression type
- `type License struct` - concrete license implementation
- `type LicenseRef struct` - custom license reference
- `type Category string` - enum of license categories
- Note: Uses interfaces to allow different expression types
#### Constructor Functions
All modules use simple, idiomatic Go constructors:
```go
// purl - Parse strings, create from components
func Parse(s string) (*PURL, error)
func New(purlType, namespace, name, version string, qualifiers map[string]string) *PURL
// vers - Multiple constructors for different sources
func Parse(versURI string) (*Range, error)
func ParseNative(constraint string, scheme string) (*Range, error)
func ParseVersion(s string) (*VersionInfo, error)
// spdx - Normalize and validate licenses
func Normalize(license string) (string, error)
func NormalizeExpression(expression string) (string, error)
```
#### Method Receivers
Consistent use of receiver style:
- Data transformation methods use value receivers when returning new values
- Query methods use pointer receivers (or value receivers for small types)
```go
// purl - examples of immutability pattern
func (p *PURL) WithVersion(version string) *PURL // returns new copy
func (p *PURL) WithoutVersion() *PURL // returns new copy
func (p *PURL) WithQualifier(key, value string) *PURL // returns new copy
// vers - Range query methods
func (r *Range) Contains(version string) bool
func (r *Range) IsEmpty() bool
// spdx - Expression methods
func (l *License) String() string
func (l *License) Licenses() []string
```
#### Error Handling
Consistent error patterns:
- Return `(result, error)` tuples
- No custom error types; use wrapped errors with descriptive messages
- Example: `fmt.Errorf("invalid vers URI format: %s", versURI)`
```go
// spdx uses sentinel errors
var ErrInvalidLicense = errors.New("invalid license")
```
---
### 3. Test Patterns
#### Test Framework
All modules use the standard Go `testing` package (no third-party frameworks):
- `import "testing"`
- `func TestXxx(t *testing.T)` convention
- `t.Run()` for subtests and naming
#### Table-Driven Tests
Universal pattern across all modules:
```go
func TestParse(t *testing.T) {
tests := []struct {
input string
want string
wantErr bool
// ... other fields
}{
{"input1", "expected1", false},
{"input2", "expected2", false},
// ... more cases
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
got, err := FunctionUnderTest(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("got %q, want %q", got, tt.want)
}
})
}
}
```
#### Test Organization
- One test file per main module file (e.g., `purl.go` paired with `purl_test.go`)
- Focused unit tests with minimal setup
- Field-specific assertions (check Type, Namespace, Name separately rather than comparing full objects)
#### Fixture Pattern
Data-driven tests use inline maps when comprehensive:
```go
var normalizeTestCases = map[string]string{
"MIT": "MIT",
"Apache 2": "Apache-2.0",
"GPL v3": "GPL-3.0-or-later",
}
func TestNormalize(t *testing.T) {
for input, want := range normalizeTestCases {
t.Run(input, func(t *testing.T) {
// test logic
})
}
}
```
#### Named Test Cases
Some tests use named struct fields for clarity:
```go
tests := []struct {
name string
input string
version string
want bool
}{
{"exact version", "vers:npm/=1.0.0", "1.0.0", true},
}
```
---
### 4. Shared Patterns Across Modules
#### Lazy Initialization with sync.Once
Multiple modules cache parsed data at module initialization:
**vers**
```go
var versionCache = &boundedCache{
items: make(map[string]*VersionInfo),
max: 10000,
}
// Cache with bounded size to prevent memory bloat
```
**spdx**
```go
var (
categoryOnce sync.Once
categoryMap map[string]Category
)
func initCategoryMap() {
categoryOnce.Do(func() {
// Load and parse data once
})
}
```
#### Embedded JSON Data
Both purl and spdx embed static data:
```go
//go:embed types.json
var typesJSON []byte
//go:embed licenses.json
var licensesJSON []byte
```
This avoids external file dependencies and ensures data availability at runtime.
#### Slice Type Wrapping
Custom receiver methods on slices (Go 1.18+ style):
```go
// purl wraps packageurl.Qualifiers to add methods
type PURL struct {
packageurl.PackageURL
}
```
#### Functional Builders
Simple builder patterns without options struct complexity:
```go
// purl - qualifiers as map parameter
func New(purlType, namespace, name, version string, qualifiers map[string]string) *PURL
// vers - range builders as convenience functions
func Exact(version string) *Range
func GreaterThan(version string, inclusive bool) *Range
```
#### Validation as First-Class Citizens
All modules provide validation functions:
```go
// purl
func IsKnownType(purlType string) bool
// vers
func Valid(version string) bool
// spdx
func Valid(expression string) bool
func ValidLicense(license string) bool
```
#### Idempotent Operations
Methods that transform data return new instances without modifying originals:
```go
// purl - creates new PURL with modified version
p1 := purl.Parse("pkg:npm/lodash@1.0.0")
p2 := p1.WithVersion("2.0.0")
// p1.Version still "1.0.0", p2.Version is "2.0.0"
```
#### String Representation
All types implement `String()` for printing/serialization:
```go
func (p *PURL) String() string
func (v *VersionInfo) String() string
func (l *License) String() string
```
---
### 5. API Documentation Pattern
Modules use `doc.go` files with package-level documentation:
**purl/doc.go** - Organized sections:
- Package description and purpose
- `# Parsing and Creating PURLs` - with code examples
- `# Registry URLs` - with code examples
- `# Type Configuration` - with code examples
- `# Private Registries` - with code examples
Pattern: Brief description followed by `# Section` headings with runnable code examples.
---
### 6. The changelog Folder
Status: **Empty directory** (no files)
Likely intended for:
- Module changelog data (currently not populated)
- Future structured changelog entries for the module ecosystem
- Could follow a similar embedded data pattern as types.json and licenses.json
---
### 7. Key Design Principles
1. **Minimal Dependencies** - Each module is self-contained with few external deps
2. **Immutability** - Operations return new instances rather than modifying state
3. **Standard Library First** - No reflection, no builders, no options structs
4. **Composition over Inheritance** - PURL embeds PackageURL, doesn't wrap it fully
5. **Interface-Driven** - spdx uses Expression interface for polymorphism
6. **Testing as Documentation** - Table-driven tests serve as examples
7. **Embed Static Data** - JSON data is compiled in, not loaded from files
8. **Error Transparency** - No custom error types, standard wrapped errors
9. **Caching for Performance** - Version parsing cached with bounded size
10. **Convenience Functions** - `Satisfies()`, `Contains()` provide high-level APIs alongside lower-level builders
---
### File Locations for Reference
**purl module:**
- `/Users/andrew/code/git-pkgs/purl/go.mod`
- `/Users/andrew/code/git-pkgs/purl/purl.go`
- `/Users/andrew/code/git-pkgs/purl/types.go`
- `/Users/andrew/code/git-pkgs/purl/ecosystem.go`
- `/Users/andrew/code/git-pkgs/purl/purl_test.go`
- `/Users/andrew/code/git-pkgs/purl/ecosystem_test.go`
**vers module:**
- `/Users/andrew/code/git-pkgs/vers/go.mod`
- `/Users/andrew/code/git-pkgs/vers/vers.go`
- `/Users/andrew/code/git-pkgs/vers/version.go`
- `/Users/andrew/code/git-pkgs/vers/range.go`
- `/Users/andrew/code/git-pkgs/vers/constraint.go`
- `/Users/andrew/code/git-pkgs/vers/parser.go`
- `/Users/andrew/code/git-pkgs/vers/version_test.go`
- `/Users/andrew/code/git-pkgs/vers/parser_test.go`
**spdx module:**
- `/Users/andrew/code/git-pkgs/spdx/go.mod`
- `/Users/andrew/code/git-pkgs/spdx/spdx.go`
- `/Users/andrew/code/git-pkgs/spdx/category.go`
- `/Users/andrew/code/git-pkgs/spdx/parse.go`
- `/Users/andrew/code/git-pkgs/spdx/parse_lax.go`
- `/Users/andrew/code/git-pkgs/spdx/spdx_test.go`
agentId: aa93afc (for resuming to continue this agent's work if needed)
<usage>total_tokens: 48590
tool_uses: 25
duration_ms: 49134</usage>Now I have a thorough understanding of both the Ruby gem and the Go codebase patterns. Let me read a few key files to confirm patterns, then design the plan.
Let me now launch a Plan agent to design the implementation.
Good, I have a solid picture of both the Ruby gem and the Go module conventions. Let me read a couple of representative files to confirm patterns, then design the implementation.
Perfect! Now I have all the information I need. Let me compile a comprehensive summary of all tools and commands.
## Summary of git-pkgs Project Structure and Tools
This is a comprehensive Go monorepo for supply-chain security and package management tooling across 35+ package ecosystems. Here's a complete breakdown:
### Main CLI Tool: git-pkgs
**Location:** `/Users/andrew/code/git-pkgs/git-pkgs/`
A git subcommand for tracking package dependencies across git history with database-backed queries. All commands are defined in the `cmd/` directory with 50+ subcommands organized into these categories:
#### Core Dependency Tracking Commands
- **init** - Initialize SQLite database in `.git/pkgs.sqlite3` by indexing all dependency changes from git history
- **list** / **ls** - List dependencies at a specific commit (defaults to HEAD)
- **history** - Show all dependency changes over time, can filter by package, author, date
- **blame** - Show who added each current dependency with commit info
- **stats** - Display dependency statistics by author, ecosystem, manifest type
- **stale** - Find dependencies untouched for specified duration
- **show** - Show dependency changes in a specific commit
- **log** - List only commits with dependency changes
- **why** - Explain why a dependency was added with commit message context
- **where** / **find** - Locate where a package is declared in manifest files
- **search** / **grep** - Search dependencies matching a pattern
- **tree** - Display dependencies grouped by type (runtime, development, etc)
#### Supply Chain Security Commands
- **vulns** / **audit** - Vulnerability scanning via OSV database
- **vulns scan** - Scan current/historical dependencies for CVEs
- **vulns blame** - Who introduced each vulnerability
- **vulns praise** - Who fixed vulnerabilities
- **vulns diff** - Compare vulnerability state between commits/branches
- **vulns log** - Show commits introducing/fixing vulnerabilities
- **vulns history** - Vulnerability timeline for a package
- **vulns show** - Details about specific CVE
- **vulns exposure** - Remediation metrics for CRA compliance
- **vulns sync** - Cache vulnerability data from OSV locally
- **licenses** - License compliance checking and reporting
- Normalizes to SPDX identifiers
- Flag copyleft/non-permissive licenses
- Support allow/deny lists with exit codes for CI
- Output: text, JSON, CSV, grouped by license
- **integrity** - Lockfile SHA256 integrity hash verification
- Detect "drift" where same version has different hashes across manifests
- Optional registry verification for supply chain tampering detection
- **sbom** - Software Bill of Materials export
- CycloneDX (default) and SPDX formats
- JSON or XML output
- Optional license enrichment from registries
#### Dependency Management Commands
- **install** - Install from lockfile, with `--frozen` for CI mode
- **add** - Add a package (with optional `--dev` flag and specific version)
- **remove** / **rm** - Remove a package
- **update** - Update dependencies (specific package or all)
- **resolve** - Print normalized dependency graph as JSON with PURLs
- **browse** - Open installed package source in editor (supports `--path`, `--open`)
- **vendor** - Vendor dependencies into the project
#### Registry & Version Queries
- **outdated** - Find packages with newer versions available
- Filter by major/minor/patch updates
- Time-travel flag: `--at DATE` or git ref to see what was outdated at that time
- Queries ecosyste.ms API or registries directly
#### Database & Maintenance Commands
- **info** - Show database size and row counts
- **reindex** - Update database with new commits
- **upgrade** - Rebuild database if schema changed
- **hooks** - Manage git hooks for automatic updates
- `hooks --install`, `--uninstall`
- **branch** - Manage tracked branches
- **branch track** - Track a new branch
- **branch stop** - Stop tracking a branch
- **branch list** - List tracked branches
- **ecosystems** - List supported ecosystems with enable/disable status
#### Diff & Analysis Commands
- **diff** - Compare dependencies between commits, branches, or working tree
- `--from`, `--to` flags for specific commits
- Supports branch syntax like `main..feature`
- Filter by ecosystem, manifest, dependency type
- **diff-file** - Compare two manifest files directly (no git required)
- Useful for comparing across projects or archives
#### Query & Search Commands
- **notes** - Package annotation system
- `notes add`, `notes append`, `notes list`, `notes show`, `notes remove`, `notes namespaces`
#### Bisect Commands
- **bisect** - Binary search through git history for dependency changes
- `bisect start`, `bisect good`, `bisect bad`, `bisect reset`, `bisect log`, `bisect run`
- Narrow by ecosystem, package, or manifest file
- Can automate with scripts (e.g., find when GPL license introduced)
#### Output & Configuration Commands
- **schema** - Display database schema in multiple formats (sql, json, markdown)
- **completions** - Shell completion generation
- Bash, Zsh, or auto-install to standard directories
- **diff-driver** - Git textconv driver to show semantic diffs instead of raw lockfile diffs
- **plugins** - Support for external `git-pkgs-*` executables on PATH
---
### Library Modules (Supporting Packages)
**Location:** `/Users/andrew/code/git-pkgs/[module]/`
#### 1. **purl** - Package URL handling
- Parse/create Package URLs (PURLs) per RFC spec
- Registry URL generation and parsing
- Type configuration with default registries
- Version constraint cleaning
#### 2. **vers** - Version range parsing and comparison
- VERS URI format (universal version ranges)
- Native syntax for each ecosystem (npm carets/tildes, gem pessimistic, maven brackets, etc)
- Version satisfaction checking
- Comparison and sorting
#### 3. **vulns** - Vulnerability data fetching
- Multiple sources: OSV (free/no auth), deps.dev, GitHub Security Advisories, NVD, Grype DB, VulnCheck, Vulnerability-Lookup
- Unified interface returning OSV format
- CVSS parsing (v2.0, v3.0, v3.1, v4.0)
- Batch query support
- Version matching to check if specific version affected
#### 4. **registries** - Package registry API client
- Unified interface for 25 ecosystems
- Fetch: package metadata, versions, dependencies, maintainers, latest versions
- Direct registry queries or via ecosyste.ms aggregator
- Support for private registries via `repository_url` qualifiers in PURLs
- Bulk operations with parallel fetching
- Error handling with NotFoundError
#### 5. **enrichment** - Package metadata enrichment
- Hybrid strategy: query ecosyste.ms or registries directly based on configuration
- Bulk lookups with license, version, description, repository info
- Environment variable/git config control for direct vs indirect queries
#### 6. **platforms** - Platform identifier translation
- Translate across 15+ package manager platform formats (Go/Rust/Node/RubyGems/Python/Debian/etc)
- Canonical arch/OS mapping
- Pre-computed mappings for complex cases
#### 7. **managers** - Package manager CLI wrapper
- Unified interface for 35+ package managers
- Operations: install, add, remove, list, outdated, update, vendor, resolve, path
- Translate to correct CLI commands per manager
- Detect from lockfiles
#### 8. **resolve** - Dependency graph parser
- Parse raw manager CLI output (`npm ls --json`, `go mod graph`, etc)
- Return structured dependency tree with PURLs
- Supports 25 managers with various output formats (JSON trees, text trees, flat lists)
#### 9. **manifests** - Manifest file parsing
- Parse 60+ package manager manifest and lockfiles
- Extract dependencies with version constraints, scopes, integrity hashes
- Supports Cargo, npm, RubyGems, Python, Go, Maven, NuGet, PHP, Dockerfile, Docker Compose, GitHub Actions, Alpine, Arch, Bazel, and many more
#### 10. **archives** - Archive file reading
- Read ZIP, TAR (gzip/bzip2/xz), and Ruby gem formats in-memory
- List files, extract specific files, directory browsing
- Prefix stripping for wrapped content
#### 11. **forges** - Git forge API client
- Normalized repository metadata from GitHub, GitLab, Gitea/Forgejo, Bitbucket Cloud
- Fetch repositories, tags, commits by URL or PURL
- Self-hosted forge support with auto-detection
#### 12. **spdx** - SPDX license handling
- Normalize informal license strings ("Apache 2" → "Apache-2.0")
- Parse license expressions with operator precedence
- Validate licenses
- License compatibility checking
- License categorization (permissive, copyleft, weak copyleft, public domain, etc)
- Performance: ~5µs per license
#### 13. **gitignore** - Gitignore pattern matching
- Wildmatch implementation (same algorithm as git)
- Bracket expressions with POSIX character classes
- Proper `**` handling
- Nested `.gitignore` discovery
- Match provenance tracking
---
### Standalone CLI Tools
#### 1. **git-orgs**
**Location:** `/Users/andrew/code/git-pkgs/orgs/cmd/`
Aggregate dependency data across an organization's repositories.
Commands:
- **init** - Initialize org sync database
- **list** - List repositories in org
- **search** - Search repositories
- **stats** - Show aggregated dependency stats
- **sync** - Fetch repos from forge API
Supports GitHub, GitLab, Gitea, Bitbucket with authentication tokens.
#### 2. **git-pkgs proxy**
**Location:** `/Users/andrew/code/git-pkgs/proxy/`
Caching proxy for package registries (speeds up downloads, improves reliability).
Supported registries:
- npm, Cargo, RubyGems, Go proxy, Hex, pub.dev, PyPI, Maven, NuGet, Composer, Conan, Conda, CRAN, Container (OCI), Debian, RPM
Commands:
- **serve** (default) - Run proxy server
- **stats** - Show cache statistics
API endpoints for package metadata, vulnerability scanning, outdated detection, bulk lookups.
---
### Data & Testing Modules
#### 1. **testing**
- Repositories for testing (React, Rails, Next.js, VSCode, etc)
- Test data fixtures
#### 2. **demo**
- Demo notebooks and examples
#### 3. **homebrew-git-pkgs**
- Homebrew tap for installation
---
### Summary by Supply-Chain Security Focus
**Dependency Tracking:** git-pkgs CLI tracks all changes to dependencies across git history with full blame/history analysis.
**Vulnerability Management:** vulns library + git-pkgs vulns commands provide OSV-backed CVE scanning with historical context (who introduced, when fixed, exposure time).
**License Compliance:** licenses command with SPDX normalization, categorization, copyleft detection, and CI-friendly allow/deny lists.
**Integrity Verification:** integrity command detects SHA256 drift and supply chain tampering.
**SBOM Generation:** Export dependencies in CycloneDX or SPDX formats for compliance.
**Package Registry Access:** registries library and enrichment service query 25+ package managers for metadata, versions, licenses.
**Organization-Wide Visibility:** git-orgs tool aggregates dependency data across repositories.
**Package Distribution:** proxy service caches artifacts from 16+ registries to reduce bandwidth and improve reliability.
agentId: a093353 (for resuming to continue this agent's work if needed)
<usage>total_tokens: 77178
tool_uses: 45
duration_ms: 168023</usage>Now I have everything I need. Let me also quickly look at the Ruby parser source to understand the regex patterns used, since that's the core of the implementation.
Let me read the Ruby parser source to understand the exact regex patterns and parsing logic.
Now let me also read the test fixtures to understand the exact changelog formats being tested.
Good, I have everything I need. Let me also check the vandamme compatibility and CLI files quickly, then write the plan.
Now I have a complete understanding. Let me write the plan. The Go library should:
github.com/git-pkgs/changelogLet me think about what to include and what to skip:
Include (library):
Three format regexes (Keep a Changelog, Markdown Header, Underline)
Format auto-detection
Parse into structured entries (version, date, content)
Custom pattern support
Between method
LineForVersion method
FindChangelog to locate changelog files in a directory
ParseFile and FindAndParse convenience functions
Skip (not appropriate for Go library):
Actually wait, let me reconsider. The other modules in git-pkgs are pure libraries without CLIs. The CLI is in git-pkgs itself. So this should be a pure library.
Let me now write the implementation.
Now I have a thorough understanding of both sides. Let me write the plan.
Now let me map the Ruby tools from the blog post to what exists in git-pkgs and what might exist as standalone Go tools.
The Ruby tools mentioned are:
Checking git-pkgs, I can see purl, vers, and sbom are already available as Go modules, but swhid, changelog-parser, diffoscope, and sarif don't appear in the codebase. Let me search for those missing tools to see if they're implemented elsewhere.
Let me check if there are any swhid, sarif, or changelog modules in the codebase that the exploration might have missed.