Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Release pipeline. Triggers on `v*` tag push; cuts a GitHub Release with
# cross-platform binaries (linux/darwin/windows × amd64/arm64), a CycloneDX
# SBOM per archive, and cosign keyless signatures for every artefact.
# SBOM per archive, multi-arch Docker images on ghcr.io, and cosign
# keyless signatures for every artefact (binaries AND container manifests).
#
# To cut a release:
# git tag vYY.NN
Expand Down Expand Up @@ -43,6 +44,22 @@ jobs:
- name: Install syft for SBOM generation
uses: anchore/sbom-action/download-syft@v0

# QEMU lets the amd64 runner build linux/arm64 image layers.
# Buildx is the modern build frontend that goreleaser's
# `dockers:` block invokes via `docker buildx build`.
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Run goreleaser
uses: goreleaser/goreleaser-action@v6
with:
Expand Down
71 changes: 71 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,77 @@ checksum:
name_template: 'checksums.txt'
algorithm: sha256

# Per-arch Docker images published to GitHub Container Registry. Each
# build target consumes the matching goreleaser-produced binaries (no
# in-image rebuild), then docker_manifests stitches the per-arch tags
# into a single multi-arch :version tag operators can pull without
# knowing what their host arch is.
#
# `use: buildx` is required for the --platform flag; release.yml sets
# up QEMU before goreleaser runs so cross-arch builds succeed on the
# amd64 GitHub runner.
dockers:
- image_templates:
- 'ghcr.io/cryptojones/networkinventoryagent:{{ .Version }}-amd64'
- 'ghcr.io/cryptojones/networkinventoryagent:latest-amd64'
dockerfile: Dockerfile.goreleaser
use: buildx
goarch: amd64
extra_files:
- README.md
- LICENSE
- SECURITY.md
- ChangeLog.md
build_flag_templates:
- --platform=linux/amd64
- --label=org.opencontainers.image.title=NetworkInventoryAgent
- --label=org.opencontainers.image.description=Two-agent network inventory with mutual watchdog
- --label=org.opencontainers.image.version={{ .Version }}
- --label=org.opencontainers.image.revision={{ .FullCommit }}
- --label=org.opencontainers.image.source=https://github.com/CryptoJones/NetworkInventoryAgent
- --label=org.opencontainers.image.licenses=Apache-2.0
- image_templates:
- 'ghcr.io/cryptojones/networkinventoryagent:{{ .Version }}-arm64'
- 'ghcr.io/cryptojones/networkinventoryagent:latest-arm64'
dockerfile: Dockerfile.goreleaser
use: buildx
goarch: arm64
extra_files:
- README.md
- LICENSE
- SECURITY.md
- ChangeLog.md
build_flag_templates:
- --platform=linux/arm64
- --label=org.opencontainers.image.title=NetworkInventoryAgent
- --label=org.opencontainers.image.description=Two-agent network inventory with mutual watchdog
- --label=org.opencontainers.image.version={{ .Version }}
- --label=org.opencontainers.image.revision={{ .FullCommit }}
- --label=org.opencontainers.image.source=https://github.com/CryptoJones/NetworkInventoryAgent
- --label=org.opencontainers.image.licenses=Apache-2.0

docker_manifests:
- name_template: 'ghcr.io/cryptojones/networkinventoryagent:{{ .Version }}'
image_templates:
- 'ghcr.io/cryptojones/networkinventoryagent:{{ .Version }}-amd64'
- 'ghcr.io/cryptojones/networkinventoryagent:{{ .Version }}-arm64'
- name_template: 'ghcr.io/cryptojones/networkinventoryagent:latest'
image_templates:
- 'ghcr.io/cryptojones/networkinventoryagent:latest-amd64'
- 'ghcr.io/cryptojones/networkinventoryagent:latest-arm64'

# cosign keyless OIDC signing for the published manifests. Uses the same
# Fulcio + Rekor flow as the binary signing in the `signs:` section.
docker_signs:
- cmd: cosign
artifacts: manifests
output: true
args:
- sign
- --yes
- --oidc-issuer=https://token.actions.githubusercontent.com
- ${artifact}

# cosign keyless OIDC signing. Requires GitHub Actions OIDC tokens, so this
# only works from the .github/workflows/release.yml job — never from a
# laptop. The transparency log entry is uploaded to Rekor by default.
Expand Down
45 changes: 45 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,51 @@ _No unreleased changes._

---

## 26.10 — 2026-05-27

Container distribution. Adds multi-arch Docker images on the GitHub
Container Registry alongside the existing binary archives, with the same
cosign keyless OIDC signing flow extended to the image manifests.

### Added

- **`ghcr.io/cryptojones/networkinventoryagent:<version>`** — multi-arch
manifest covering linux/amd64 + linux/arm64. `:latest` resolves to
the same image as the most recent `vYY.NN` tag. Default entrypoint is
`agent`; `wintermute` and `neuromancer` are present in the same image
and reachable via `--entrypoint /usr/local/bin/wintermute` etc.
- **`Dockerfile.goreleaser`** — slim COPY-only Dockerfile consumed by
goreleaser. Pre-built binaries are copied in rather than recompiled
per arch (the host-level goreleaser build matrix already produced
them). The existing top-level `Dockerfile` is unchanged so
`docker build .` from a checkout still works.
- **`cosign` signing on the published manifests.** Verify with:
```
cosign verify ghcr.io/cryptojones/networkinventoryagent:26.10 \
--certificate-identity-regexp 'https://github.com/CryptoJones/NetworkInventoryAgent/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
```

### Changed

- **`.github/workflows/release.yml`** now sets up QEMU + Docker Buildx
and logs in to ghcr.io before invoking goreleaser, so the cross-arch
`linux/arm64` layer builds succeed on the amd64-only GitHub runner.
- **README** gains a Docker section with the `docker pull` quickstart
and the `cosign verify` snippet.

### Notes

- The image's default entrypoint is `agent` (standalone single-agent
binary). For the Wintermute/Neuromancer pair, the existing
`docker-compose.yml` still applies — point its `image:` at
`ghcr.io/cryptojones/networkinventoryagent:26.10` and you skip the
`docker build` step.
- Pulls are unauthenticated for public images; `docker login ghcr.io`
is only needed if a future release flips visibility to private.

---

## 26.09 — 2026-05-27

Post-Planning.md tightening pass — clears the lint debt that 26.06's
Expand Down
41 changes: 41 additions & 0 deletions Dockerfile.goreleaser
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Dockerfile.goreleaser — slim image consumed by `goreleaser release`.
#
# The main Dockerfile builds the binaries inside the image (multi-stage,
# good for `docker build .`). goreleaser already cross-compiles every
# binary at the host level, so this variant just COPYs the resulting
# artefacts in and avoids the duplicated Go toolchain pass per arch.
#
# Pinned by sha256 so rebuilds are reproducible and Renovate has a
# concrete handle to bump (renovate.json automerges digest updates).
FROM alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc

RUN addgroup -S inventory && adduser -S -G inventory inventory

# goreleaser places each per-binary build under its own dist subdir and
# passes the directory contents as the docker build context, so the
# binaries are at the top of the build context here — no per-arch dance.
COPY agent /usr/local/bin/agent
COPY wintermute /usr/local/bin/wintermute
COPY neuromancer /usr/local/bin/neuromancer
COPY console /usr/local/bin/console

# Bundled docs / configs so `docker run --rm <image> cat /etc/inventory/...`
# gives operators reference material without a separate volume mount.
COPY README.md /usr/share/doc/inventory/README.md
COPY LICENSE /usr/share/doc/inventory/LICENSE
COPY SECURITY.md /usr/share/doc/inventory/SECURITY.md
COPY ChangeLog.md /usr/share/doc/inventory/ChangeLog.md

RUN mkdir -p /data && chown inventory:inventory /data
VOLUME ["/data"]

USER inventory

# Default ports — health 8080, admin 9090. Override at run time with
# -e or by mounting a config file under /data and pointing -config at it.
EXPOSE 8080 9090

# The `agent` entrypoint is the standalone single-agent binary. To run
# Wintermute/Neuromancer instead:
# docker run --rm <image> --entrypoint /usr/local/bin/wintermute ...
ENTRYPOINT ["/usr/local/bin/agent"]
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,33 @@ No C toolchain is required. The SQLite driver (`modernc.org/sqlite`) is pure Go.

## Installation

### Docker (multi-arch, signed)

```bash
docker pull ghcr.io/cryptojones/networkinventoryagent:latest
docker run --rm ghcr.io/cryptojones/networkinventoryagent:latest -version
```

The `:latest` and `:<version>` tags both point at multi-arch manifests
(linux/amd64 + linux/arm64); your Docker client picks the right one for
the host. The manifests are signed with `cosign` keyless OIDC — verify with:

```bash
cosign verify \
--certificate-identity-regexp 'https://github.com/CryptoJones/NetworkInventoryAgent/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/cryptojones/networkinventoryagent:<version>
```

The image's default entrypoint is `agent` (standalone). To run the paired
Wintermute/Neuromancer mode, override the entrypoint:

```bash
docker run --rm \
--entrypoint /usr/local/bin/wintermute \
ghcr.io/cryptojones/networkinventoryagent:latest -version
```

### Pre-built binaries (signed)

Tagged releases at <https://github.com/CryptoJones/NetworkInventoryAgent/releases>
Expand Down
Loading