-
Notifications
You must be signed in to change notification settings - Fork 0
build(packaging): ship structured-proxy as RPM/DEB to repo.sw.foundation #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
36570de
build(packaging): add RPM/DEB packaging and release workflow
polaz 34191c3
fix(packaging): compile the redis feature into release binaries
polaz e47975f
fix(packaging): do not mask config ownership failures in postinst
polaz dae2c73
docs(packaging): note sandbox-readable paths for configured files
polaz eb24952
fix(packaging): declare both published Fedora arches in manifest
polaz 13cefaf
fix(packaging): check out the released tag in package jobs
polaz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,299 @@ | ||
| name: Release | ||
|
|
||
| # Builds native packages for a published release and ships them to | ||
| # repo.sw.foundation. Runs after release-plz creates the GitHub release/tag; | ||
| # can also be re-run manually against an existing tag. | ||
| on: | ||
| release: | ||
| types: [created] | ||
| workflow_dispatch: | ||
| inputs: | ||
| tag_name: | ||
| description: "Release tag to build (e.g. v2.1.0)" | ||
| required: true | ||
|
|
||
| env: | ||
| CARGO_TERM_COLOR: always | ||
| CARGO_INCREMENTAL: 0 | ||
| TAG_NAME: ${{ github.event.release.tag_name || inputs.tag_name }} | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| build-musl: | ||
| name: Build musl (${{ matrix.target }}) | ||
| runs-on: ${{ matrix.runs-on }} | ||
| strategy: | ||
| matrix: | ||
| include: | ||
| - target: x86_64-unknown-linux-musl | ||
| artifact: structured-proxy-linux-amd64 | ||
| runs-on: ubuntu-latest | ||
| - target: aarch64-unknown-linux-musl | ||
| artifact: structured-proxy-linux-arm64 | ||
| runs-on: ubuntu-24.04-arm | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
polaz marked this conversation as resolved.
|
||
| with: | ||
| # Build from the exact released tag, so a manual re-run for an older | ||
| # tag packages that tag's commit rather than whatever ref triggered | ||
| # the workflow (which would mislabel the assets with the wrong version). | ||
| ref: ${{ env.TAG_NAME }} | ||
|
|
||
| - name: Install Rust + musl target | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| targets: ${{ matrix.target }} | ||
|
|
||
| - name: Install musl tools | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y musl-tools | ||
|
|
||
| - uses: Swatinem/rust-cache@v2 | ||
| with: | ||
| key: ${{ matrix.target }} | ||
|
|
||
| - name: Build static binary | ||
| run: | | ||
| # `redis` is compiled in so the packaged `shield.redis_url` config | ||
| # works (multi-instance shared rate limits) instead of silently | ||
| # falling back to per-process counters. It is a pure-Rust dependency, | ||
| # so it stays musl-static-clean. | ||
| cargo build --release --target ${{ matrix.target }} --features redis --bin structured-proxy | ||
| strip target/${{ matrix.target }}/release/structured-proxy || true | ||
|
polaz marked this conversation as resolved.
|
||
|
|
||
| - name: Package | ||
| run: | | ||
| cp target/${{ matrix.target }}/release/structured-proxy \ | ||
| structured-proxy-${{ env.TAG_NAME }}-${{ matrix.artifact }} | ||
|
|
||
| - name: Upload artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: ${{ matrix.artifact }} | ||
| path: structured-proxy-${{ env.TAG_NAME }}-${{ matrix.artifact }} | ||
| retention-days: 1 | ||
|
|
||
| - name: Attach binary to release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| tag_name: ${{ env.TAG_NAME }} | ||
| files: structured-proxy-${{ env.TAG_NAME }}-${{ matrix.artifact }} | ||
|
|
||
| build-rpm: | ||
| name: Build RPM (${{ matrix.fedora }}/${{ matrix.arch }}) | ||
| runs-on: ${{ matrix.runs-on }} | ||
| needs: build-musl | ||
| container: | ||
| image: registry.fedoraproject.org/fedora:${{ matrix.fedora }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - { fedora: "42", arch: x86_64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 } | ||
| - { fedora: "42", arch: aarch64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 } | ||
| - { fedora: "43", arch: x86_64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 } | ||
| - { fedora: "43", arch: aarch64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 } | ||
| - { fedora: "44", arch: x86_64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 } | ||
| - { fedora: "44", arch: aarch64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 } | ||
| steps: | ||
| - name: Install rpmbuild + helpers | ||
| run: | | ||
| dnf install -y --setopt=install_weak_deps=False \ | ||
| rpm-build rpmdevtools systemd-rpm-macros findutils tar | ||
| rpmdev-setuptree | ||
|
|
||
| - uses: actions/checkout@v6 | ||
| with: | ||
| # Build from the exact released tag, so a manual re-run for an older | ||
| # tag packages that tag's commit rather than whatever ref triggered | ||
| # the workflow (which would mislabel the assets with the wrong version). | ||
| ref: ${{ env.TAG_NAME }} | ||
|
|
||
| - name: Download prebuilt binary | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: ${{ matrix.bin_artifact }} | ||
| path: /tmp/bin/ | ||
|
|
||
| - name: Stage sources | ||
| run: | | ||
| VERSION=$(echo "${{ env.TAG_NAME }}" | sed 's/^v//') | ||
| echo "VERSION=$VERSION" >> "$GITHUB_ENV" | ||
| BIN=$(find /tmp/bin -type f -name 'structured-proxy-*' | head -1) | ||
| install -m 0755 "$BIN" ~/rpmbuild/SOURCES/structured-proxy | ||
| install -m 0644 packaging/structured-proxy.service ~/rpmbuild/SOURCES/structured-proxy.service | ||
| install -m 0644 packaging/config.yaml ~/rpmbuild/SOURCES/config.yaml | ||
| install -m 0644 packaging/structured-proxy.sysusers ~/rpmbuild/SOURCES/structured-proxy.sysusers | ||
| install -m 0644 LICENSE ~/rpmbuild/SOURCES/LICENSE | ||
| install -m 0644 README.md ~/rpmbuild/SOURCES/README.md | ||
|
|
||
| - name: Build RPM | ||
| run: | | ||
| rpmbuild -bb \ | ||
| --define "_topdir $HOME/rpmbuild" \ | ||
| --define "version $VERSION" \ | ||
| --target ${{ matrix.arch }} \ | ||
| packaging/rpm/structured-proxy.spec | ||
| find ~/rpmbuild/RPMS -name '*.rpm' -print | ||
|
|
||
| - name: Lint with rpmlint (advisory) | ||
| continue-on-error: true | ||
| run: | | ||
| dnf install -y --setopt=install_weak_deps=False rpmlint || true | ||
| rpmlint $(find ~/rpmbuild/RPMS -name '*.rpm') || true | ||
|
|
||
| - name: Stage artifact | ||
| run: | | ||
| mkdir -p /tmp/artifacts | ||
| cp ~/rpmbuild/RPMS/${{ matrix.arch }}/*.rpm /tmp/artifacts/ | ||
|
|
||
| - name: Upload RPM artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: rpm-fc${{ matrix.fedora }}-${{ matrix.arch }} | ||
| path: /tmp/artifacts/*.rpm | ||
| if-no-files-found: error | ||
|
|
||
| - name: Attach RPM to release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| tag_name: ${{ env.TAG_NAME }} | ||
| files: /tmp/artifacts/*.rpm | ||
|
|
||
| build-deb: | ||
| name: Build DEB (${{ matrix.codename }}/${{ matrix.arch }}) | ||
| runs-on: ${{ matrix.runs-on }} | ||
| needs: build-musl | ||
| container: | ||
| image: ${{ matrix.image }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - { codename: bookworm, image: "debian:bookworm", arch: amd64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 } | ||
| - { codename: bookworm, image: "debian:bookworm", arch: arm64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 } | ||
| - { codename: jammy, image: "ubuntu:jammy", arch: amd64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 } | ||
| - { codename: jammy, image: "ubuntu:jammy", arch: arm64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 } | ||
| - { codename: noble, image: "ubuntu:noble", arch: amd64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 } | ||
| - { codename: noble, image: "ubuntu:noble", arch: arm64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 } | ||
| steps: | ||
| - name: Install debhelper + dpkg-dev | ||
| env: | ||
| DEBIAN_FRONTEND: noninteractive | ||
| run: | | ||
| apt-get update | ||
| # build-essential satisfies the implicit Build-Depends pulled in by | ||
| # debhelper-compat (= 13); without it dpkg-checkbuilddeps aborts. | ||
| apt-get install -y --no-install-recommends \ | ||
| debhelper dpkg-dev dh-make ca-certificates findutils \ | ||
| build-essential adduser | ||
|
|
||
| - uses: actions/checkout@v6 | ||
| with: | ||
| # Build from the exact released tag, so a manual re-run for an older | ||
| # tag packages that tag's commit rather than whatever ref triggered | ||
| # the workflow (which would mislabel the assets with the wrong version). | ||
| ref: ${{ env.TAG_NAME }} | ||
|
|
||
| - name: Download prebuilt binary | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: ${{ matrix.bin_artifact }} | ||
| path: /tmp/bin/ | ||
|
|
||
| - name: Assemble source tree | ||
| run: | | ||
| VERSION=$(echo "${{ env.TAG_NAME }}" | sed 's/^v//') | ||
| echo "VERSION=$VERSION" >> "$GITHUB_ENV" | ||
| BUILD=/tmp/structured-proxy-$VERSION | ||
| mkdir -p "$BUILD/packaging" | ||
| BIN=$(find /tmp/bin -type f -name 'structured-proxy-*' | head -1) | ||
| install -m 0755 "$BIN" "$BUILD/structured-proxy" | ||
| cp -r packaging/structured-proxy.service packaging/config.yaml \ | ||
| packaging/structured-proxy.sysusers \ | ||
| "$BUILD/packaging/" | ||
| cp -r packaging/deb/debian "$BUILD/" | ||
| cp LICENSE README.md "$BUILD/" | ||
| # Rewrite the placeholder changelog with the actual version. | ||
| cat > "$BUILD/debian/changelog" <<CHANGELOG | ||
| structured-proxy ($VERSION) unstable; urgency=medium | ||
|
|
||
| * Automated release $VERSION; see CHANGELOG.md upstream. | ||
|
|
||
| -- Release Bot <oss@sw.foundation> $(date -R) | ||
| CHANGELOG | ||
|
polaz marked this conversation as resolved.
|
||
| echo "BUILD_DIR=$BUILD" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Build DEB | ||
| working-directory: ${{ env.BUILD_DIR }} | ||
| run: | | ||
| dpkg-buildpackage -us -uc -b -a${{ matrix.arch }} | ||
| ls -la .. | ||
|
polaz marked this conversation as resolved.
|
||
|
|
||
| - name: Lint with lintian (advisory) | ||
| continue-on-error: true | ||
| run: | | ||
| apt-get install -y --no-install-recommends lintian || true | ||
| lintian /tmp/structured-proxy_*_${{ matrix.arch }}.deb || true | ||
|
|
||
| - name: Stage artifact | ||
| run: | | ||
| mkdir -p /tmp/artifacts | ||
| cp /tmp/structured-proxy_${VERSION}_${{ matrix.arch }}.deb /tmp/artifacts/ | ||
|
|
||
| - name: Upload DEB artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: deb-${{ matrix.codename }}-${{ matrix.arch }} | ||
| path: /tmp/artifacts/*.deb | ||
| if-no-files-found: error | ||
|
|
||
| - name: Attach DEB to release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| tag_name: ${{ env.TAG_NAME }} | ||
| files: /tmp/artifacts/*.deb | ||
|
polaz marked this conversation as resolved.
|
||
|
|
||
| publish-repo: | ||
| name: Publish to repo.sw.foundation | ||
| runs-on: ubuntu-latest | ||
| needs: [build-rpm, build-deb] | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| # Build from the exact released tag, so a manual re-run for an older | ||
| # tag packages that tag's commit rather than whatever ref triggered | ||
| # the workflow (which would mislabel the assets with the wrong version). | ||
| ref: ${{ env.TAG_NAME }} | ||
|
|
||
| - name: Repo metadata | ||
| run: | | ||
| mkdir -p /tmp/repo-meta | ||
| cp packaging/manifest.json /tmp/repo-meta/ | ||
|
|
||
| - name: Upload repo-meta artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: repo-meta-structured-proxy | ||
| path: /tmp/repo-meta/ | ||
|
|
||
| - name: Generate release bot token | ||
| id: app-token | ||
| uses: actions/create-github-app-token@v1 | ||
| with: | ||
| app-id: ${{ secrets.RELEASER_APP_ID }} | ||
| private-key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }} | ||
| repositories: repo | ||
|
|
||
| - name: Trigger repo publish | ||
| env: | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| run: | | ||
| gh api repos/structured-world/repo/dispatches \ | ||
| --method POST \ | ||
| -f event_type=publish-from-structured-proxy \ | ||
| -f client_payload[structured_proxy_run_id]="${{ github.run_id }}" \ | ||
| -f client_payload[structured_proxy_repo]="${{ github.repository }}" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # structured-proxy configuration. | ||
| # | ||
| # This is a TEMPLATE. The service ships disabled because the proxy needs a | ||
| # service-specific config before it can do anything useful: at minimum an | ||
| # upstream gRPC address and one proto descriptor set. Edit this file, then: | ||
| # | ||
| # sudo systemctl enable --now structured-proxy | ||
| # | ||
| # Read by /usr/lib/systemd/system/structured-proxy.service via: | ||
| # ExecStart=/usr/bin/structured-proxy --config /etc/structured-proxy/config.yaml | ||
| # | ||
| # Marked as a config file in the RPM/DEB package, so local edits survive | ||
| # upgrades. Full reference: https://github.com/structured-world/structured-proxy | ||
| # | ||
| # Any file path referenced below (descriptor sets, JWT/OIDC PEM keys, JWKS | ||
| # caches) must live somewhere the hardened unit can read. The service runs with | ||
| # ProtectHome=yes and ProtectSystem=strict, so /home, /root and /run/user are | ||
| # hidden and most of the filesystem is read-only — keep referenced files under | ||
| # /etc/structured-proxy (readable) rather than an operator home directory. | ||
|
|
||
| # HTTP listen address for the transcoded REST surface. | ||
| listen: | ||
| http: "0.0.0.0:8080" | ||
|
|
||
| # Upstream gRPC service this proxy transcodes to. REQUIRED — replace with your | ||
| # service address. | ||
| upstream: | ||
| default: "http://127.0.0.1:50051" | ||
|
|
||
| # Pre-compiled proto descriptor sources (one or more, merged into one pool). | ||
| # REQUIRED for any routes to be generated. Build one with: | ||
| # buf build -o my-service.descriptor.bin | ||
| # # or: protoc --descriptor_set_out=my-service.descriptor.bin --include_imports *.proto | ||
| descriptors: [] | ||
| # - file: "/etc/structured-proxy/my-service.descriptor.bin" | ||
|
|
||
| # Service identity (drives the /health response and metrics namespace). | ||
| service: | ||
| name: "structured-proxy" | ||
|
|
||
| # CORS: empty list = permissive (dev). List exact origins for production. | ||
| cors: | ||
| origins: [] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| structured-proxy (0.0.0) unstable; urgency=medium | ||
|
|
||
| * Placeholder. CI overwrites this file with the real changelog entry | ||
| generated from the release tag before invoking dpkg-buildpackage. | ||
|
|
||
| -- Release Bot <oss@sw.foundation> Mon, 11 May 2026 00:00:00 +0000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| Source: structured-proxy | ||
| Section: net | ||
| Priority: optional | ||
| Maintainer: Structured World Foundation <oss@sw.foundation> | ||
| Build-Depends: debhelper-compat (= 13) | ||
| Standards-Version: 4.6.2 | ||
| Homepage: https://github.com/structured-world/structured-proxy | ||
|
|
||
| Package: structured-proxy | ||
| Architecture: amd64 arm64 | ||
| Depends: ${misc:Depends}, systemd, adduser | ||
| Description: Universal gRPC to REST transcoding proxy | ||
| structured-proxy is a config-driven gRPC to REST transcoding proxy. One | ||
| binary serves any gRPC service from a proto descriptor set and a YAML config, | ||
| with no code generation and no custom handlers. | ||
| . | ||
| The service ships disabled: set an upstream address and proto descriptors in | ||
| /etc/structured-proxy/config.yaml, then enable it with systemctl. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.