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
60 changes: 57 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install pytest pytest-cov cryptography
- run: pip install pytest pytest-cov cryptography pyyaml
- name: Run unit and integration tests
run: pytest -m "not e2e" --cov=buncker --cov=buncker_fetch --cov=shared --cov-fail-under=80
- name: Run e2e tests
Expand Down Expand Up @@ -57,6 +57,56 @@ jobs:
path: dist/*.deb
retention-days: 30

build-rpm:
needs: test
runs-on: ubuntu-latest
container: fedora:latest
steps:
- uses: actions/checkout@v4
- name: Install build tools
run: dnf install -y rpm-build python3 make
- name: Build .rpm packages
run: make build-rpm
- name: Verify .rpm packages
run: |
for rpm in dist/*.rpm; do
echo "--- $rpm ---"
rpm -qpi "$rpm"
rpm -qpl "$rpm"
done
- name: Upload .rpm artifacts
uses: actions/upload-artifact@v4
with:
name: rpm-packages
path: dist/*.rpm
retention-days: 30

test-rpm-install:
needs: build-rpm
runs-on: ubuntu-latest
container: fedora:latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: rpm-packages
path: dist/
- name: Install RPMs
run: |
dnf install -y python3-cryptography python3-pyyaml
rpm -ivh dist/*.noarch.rpm
- name: Verify installation
run: |
test -x /usr/bin/buncker
test -x /usr/bin/buncker-fetch
test -f /usr/lib/systemd/system/buncker.service
test -f /etc/logrotate.d/buncker
test -d /usr/lib/buncker/buncker
test -d /usr/lib/buncker/shared
test -d /usr/lib/buncker-fetch/buncker_fetch
test -d /usr/lib/buncker-fetch/shared
echo "RPM installation verified OK"

test-deb-install:
needs: build-deb
runs-on: ubuntu-latest
Expand All @@ -73,7 +123,7 @@ jobs:

release:
if: startsWith(github.ref, 'refs/tags/v')
needs: [build-deb, test-deb-install]
needs: [build-deb, test-deb-install, build-rpm, test-rpm-install]
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -83,7 +133,11 @@ jobs:
with:
name: deb-packages
path: dist/
- uses: actions/download-artifact@v4
with:
name: rpm-packages
path: dist/
- name: Create GitHub Release
run: gh release create "${{ github.ref_name }}" dist/*.deb --title "Buncker ${{ github.ref_name }}" --generate-notes
run: gh release create "${{ github.ref_name }}" dist/*.deb dist/*.rpm --title "Buncker ${{ github.ref_name }}" --generate-notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36 changes: 35 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.0.0] - 2026-03-09

### Added

- Docker Compose analysis: `buncker analyze --compose <file>` parses `docker-compose.yml` to resolve all service images and Dockerfiles in one pass
- Remote Compose analysis via `compose_content` / `compose_path` fields in `POST /admin/analyze`
- RPM packaging for RHEL/Fedora: `.spec` files, `make build-rpm` target, CI build and install jobs
- Logrotate configuration for `/var/log/buncker/*.log` (daily rotation, 30 days retention, compress + copytruncate)
- `--restrict-oci` flag on `buncker serve`: requires Bearer token on `/v2/*` endpoints with `WWW-Authenticate` challenge per OCI Distribution Spec
- `oci.restrict` config option (default: false) for persistent OCI auth restriction
- Manifest cache TTL: `manifest_ttl` config option (default: 30 days) triggers warnings for stale manifests during analyze
- `--refresh-stale` flag on `buncker generate-manifest` to include stale manifests for re-download by buncker-fetch
- `stale_manifests` count in `GET /admin/status` response
- `stale_manifests` list in analyze response for programmatic detection

### Security

- Tar extraction: validate member paths for `..` and absolute paths on Python < 3.12 (zip-slip protection)
- TLS: enforce minimum TLS 1.2 and restrict cipher suites to ECDHE+AESGCM/CHACHA20
- API tokens: warn in logs if `api-tokens.json` has insecure file permissions on load
- Auth: reject empty Bearer token value early instead of relying on comparison fallthrough
- Import: validate `X-Buncker-Checksum` header as strict `sha256:<64 hex chars>` format
- Store: set blob and metadata files to mode 0600 (no world-readable defaults)
- Store: reject symlinks at blob destination path before write
- Crypto: bump PBKDF2 iterations for env key derivation from 100k to 600k (OWASP minimum)
- TLS: use RSA-4096 for self-signed CA and server certificates (was 2048)
- HTTP: add `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Cache-Control: no-store` on all responses

### Changed

- `packaging/buncker/debian/control` now depends on `python3-yaml` for Compose support
- `.deb` install file updated with `auth.py` and `compose.py` modules

## [0.9.0] - 2026-03-09

### Added
Expand Down Expand Up @@ -250,7 +283,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- GitHub templates for issues (bug report, feature request) and pull requests
- Conventional Commits convention and branching strategy documented

[Unreleased]: https://github.com/Rwx-G/Buncker/compare/v0.9.0...HEAD
[Unreleased]: https://github.com/Rwx-G/Buncker/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/Rwx-G/Buncker/compare/v0.9.0...v1.0.0
[0.9.0]: https://github.com/Rwx-G/Buncker/compare/v0.8.1...v0.9.0
[0.8.1]: https://github.com/Rwx-G/Buncker/compare/v0.8.0...v0.8.1
[0.8.0]: https://github.com/Rwx-G/Buncker/compare/v0.7.0...v0.8.0
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ buncker/
├── buncker/ # Offline daemon
├── buncker_fetch/ # Online CLI
├── tests/ # Tests mirroring source structure
├── packaging/ # .deb build files
├── packaging/ # .deb and .rpm build files
└── docs/ # PRD, architecture, stories
```

## Code Standards

- **Python >= 3.11**, type hints on public signatures
- **No pip, no venv** - only stdlib + `python3-cryptography` (apt)
- **No pip, no venv** - only stdlib + `python3-cryptography` + `python3-yaml` (apt/dnf)
- **Linting:** ruff (rules: E, F, W, I, UP, B, SIM)
- **Formatting:** ruff format
- **Tests:** pytest, 80% coverage minimum, 100% on crypto module
Expand Down Expand Up @@ -66,8 +66,8 @@ ci: add .deb build step to workflow

### Version Tags

Releases are tagged with semantic versions: `v0.5.0`, `v0.6.0`, etc.
Tags trigger the CI build-deb job, producing `.deb` artifacts uploaded to GitHub Releases.
Releases are tagged with semantic versions: `v0.5.0`, `v1.0.0`, etc.
Tags trigger the CI build jobs, producing `.deb` and `.rpm` artifacts uploaded to GitHub Releases.

## Workflow

Expand Down
35 changes: 34 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: lint test build build-deb clean
.PHONY: lint test build build-deb build-rpm clean

VERSION := $(shell python3 -c "import buncker; print(buncker.__version__)" 2>/dev/null || echo "0.5.0")
DIST := dist
Expand Down Expand Up @@ -59,10 +59,43 @@ define build_pkg
mkdir -p $(STAGE)/lib/systemd/system; \
sed 's/\r$$//' packaging/$(DEBDIR)/debian/$(PKG).service > $(STAGE)/lib/systemd/system/$(PKG).service; \
fi
@if [ -f packaging/$(DEBDIR)/logrotate ]; then \
mkdir -p $(STAGE)/etc/logrotate.d; \
sed 's/\r$$//' packaging/$(DEBDIR)/logrotate > $(STAGE)/etc/logrotate.d/$(PKG); \
fi
@# Build
@dpkg-deb --build --root-owner-group $(STAGE) $(DIST)/$(PKG)_$(VERSION)_all.deb
@rm -rf $(STAGE)
endef

build-rpm: $(DIST)/buncker-$(VERSION)-1.noarch.rpm $(DIST)/buncker-fetch-$(VERSION)-1.noarch.rpm
@echo "Built .rpm packages in $(DIST)/"

$(DIST)/buncker-$(VERSION)-1.noarch.rpm:
@mkdir -p $(DIST)
$(call build_rpm,buncker)

$(DIST)/buncker-fetch-$(VERSION)-1.noarch.rpm:
@mkdir -p $(DIST)
$(call build_rpm,buncker-fetch)

# build_rpm(pkg_name)
# Assembles an .rpm package using rpmbuild with project root as source.
define build_rpm
$(eval PKG := $(1))
$(eval RPMTOP := $(DIST)/.rpmbuild-$(PKG))
@rm -rf $(RPMTOP)
@mkdir -p $(RPMTOP)/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
@# Copy spec with patched version
@sed 's/^Version:.*/Version: $(VERSION)/' packaging/$(PKG)/rpm/$(PKG).spec > $(RPMTOP)/SPECS/$(PKG).spec
@# Link project root as source
@ln -sf $(CURDIR) $(RPMTOP)/SOURCES
@rpmbuild --define "_topdir $(CURDIR)/$(RPMTOP)" \
--define "_sourcedir $(CURDIR)" \
-bb $(RPMTOP)/SPECS/$(PKG).spec
@cp $(RPMTOP)/RPMS/noarch/$(PKG)-$(VERSION)-*.noarch.rpm $(DIST)/
@rm -rf $(RPMTOP)
endef

clean:
rm -rf $(DIST)
Loading