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
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "flagd dev container",
// Image details: https://github.com/devcontainers/images/tree/main/src/go
"image": "mcr.microsoft.com/devcontainers/go:1.24",
"image": "mcr.microsoft.com/devcontainers/go:1.27",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ on:
- "README.md"
- "docs/**"

env:
# The toolchain determines which FIPS snapshots exist, so pin it.
GOTOOLCHAIN: local

jobs:
lint:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -63,6 +67,66 @@ jobs:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@e0b68c6749509c5f83f984dd99a76a1c1a231044 # v4

fips:
name: FIPS 140-3
runs-on: ubuntu-latest
env:
GOPATH: /home/runner/work/open-feature/flagd
GOBIN: /home/runner/work/open-feature/flagd/bin
steps:
- name: Checkout repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
- name: Setup go
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5
with:
go-version-file: 'flagd/go.mod'
- run: make workspace-init

# Fails if any tested code path reaches a non-approved algorithm.
- name: Test the FIPS variant with strict enforcement
run: make test-fips
Comment thread
JamieSinn marked this conversation as resolved.

- name: Build both variants
run: |
set -euo pipefail
make build-flagd
make build-flagd-fips

- name: The standard build must not claim FIPS
run: |
set -euo pipefail
./bin/flagd version | grep -q 'build variant: standard'
./bin/flagd version | grep -q 'FIPS 140-3 mode: disabled'
# The standard build must still run with FIPS mode forced off.
GODEBUG=fips140=off ./bin/flagd version >/dev/null

- name: The FIPS build must carry and require the certified module
run: |
set -euo pipefail
go version -m ./bin/flagd-fips | grep -q 'GOFIPS140=v1\.0\.0'
go version -m ./bin/flagd-fips | grep -q 'DefaultGODEBUG=fips140=on'
go version -m ./bin/flagd-fips | grep -q -- '-tags=fips140'
./bin/flagd-fips version | grep -q 'build variant: fips'
./bin/flagd-fips version | grep -q 'FIPS 140-3 mode: enabled'
# Enforcement is unconditional: no flag can turn it off.
if GODEBUG=fips140=off ./bin/flagd-fips start -f file:./config/samples/example_flags.flagd.json; then
echo "::error::the FIPS build started with FIPS mode disabled"; exit 1
fi

- name: A fips140-tagged build without GOFIPS140 must refuse to start
run: |
set -euo pipefail
go build -tags fips140 -o /tmp/flagd-mismatch ./flagd
if /tmp/flagd-mismatch start -f file:./config/samples/example_flags.flagd.json; then
echo "::error::a mislabelled FIPS build started"; exit 1
fi

- name: Check the cryptographic dependency closure has not drifted
run: |
make fips-closure
git diff --exit-code docs/reference/fips-crypto-closure.txt \
|| { echo "::error::cryptographic dependency closure changed; review docs/reference/fips-140-3.md and commit the regenerated closure"; exit 1; }

docker-local:
runs-on: ubuntu-latest

Expand Down
62 changes: 56 additions & 6 deletions .github/workflows/release-please.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ env:
PUBLISHABLE_ITEMS: '["flagd","flagd-proxy"]'
REGISTRY: ghcr.io
REPO_OWNER: ${{ github.repository_owner }}
DEFAULT_GO_VERSION: '~1.25'
DEFAULT_GO_VERSION: '~1.27'
PUBLIC_KEY_FILE: publicKey.pub
GOPRIVATE: buf.build/gen/go
# The toolchain determines which FIPS snapshots exist, so pin it.
GOTOOLCHAIN: local

name: Release Please
jobs:
Expand Down Expand Up @@ -120,12 +122,34 @@ jobs:
VERSION=${{ env.VERSION }}
COMMIT=${{ github.sha }}
DATE=${{ needs.release-please.outputs.date }}
- name: Build FIPS variant
id: build-fips
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./${{ matrix.path }}/build.Dockerfile
platforms: linux/amd64,linux/arm64
provenance: mode=max
sbom: true
push: true
tags: |
${{ env.REGISTRY }}/${{ env.REPO_OWNER }}/${{ matrix.path }}:latest-fips
Comment thread
JamieSinn marked this conversation as resolved.
${{ env.REGISTRY }}/${{ env.REPO_OWNER }}/${{ matrix.path }}:${{ env.VERSION }}-fips
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ env.VERSION }}
COMMIT=${{ github.sha }}
DATE=${{ needs.release-please.outputs.date }}
FIPS=on

- name: Install Cosign
uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4

- name: Sign the image
- name: Sign the images
run: |
cosign sign --yes --key env://COSIGN_PRIVATE_KEY ${{ env.REGISTRY }}/${{ env.REPO_OWNER }}/${{ matrix.path }}@${{ steps.build.outputs.digest }}
cosign sign --yes --key env://COSIGN_PRIVATE_KEY ${{ env.REGISTRY }}/${{ env.REPO_OWNER }}/${{ matrix.path }}@${{ steps.build-fips.outputs.digest }}
cosign public-key --key env://COSIGN_PRIVATE_KEY --outfile ${{ env.PUBLIC_KEY_FILE }}
env:
COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}}
Expand Down Expand Up @@ -189,10 +213,6 @@ jobs:
run: |
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ${{ env.BUILD_ARGS }} -o ./${{ matrix.path }}_linux_x86_64 ./${{ matrix.path }}/main.go
tar -cvzf ${{ matrix.path }}_${{ env.VERSION_NO_PREFIX }}_Linux_x86_64.tar.gz ./${{ matrix.path }}_linux_x86_64 ./LICENSE ./CHANGELOG.md ./README.md ./sbom.xml
- name: build linux i386
run: |
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build ${{ env.BUILD_ARGS }} -o ./${{ matrix.path }}_linux_i386 ./${{ matrix.path }}/main.go
tar -cvzf ${{ matrix.path }}_${{ env.VERSION_NO_PREFIX }}_Linux_i386.tar.gz ./${{ matrix.path }}_linux_i386 ./LICENSE ./CHANGELOG.md ./README.md ./sbom.xml
# Windows artifacts use .zip archive
- name: build windows x86_64
run: |
Expand All @@ -202,6 +222,36 @@ jobs:
run: |
env CGO_ENABLED=0 GOOS=windows GOARCH=386 go build ${{ env.BUILD_ARGS }} -o ./${{ matrix.path }}_windows_i386 ./${{ matrix.path }}/main.go
zip -r ${{ matrix.path }}_${{ env.VERSION_NO_PREFIX }}_Windows_i386.zip ./${{ matrix.path }}_windows_i386 ./LICENSE ./CHANGELOG.md ./README.md ./sbom.xml

# FIPS variant. Fewer targets than the standard build: FIPS mode is
# unsupported on windows/386, and linux/386 is not a validated operating
# environment for the module.
- name: build FIPS variant
env:
# The CMVP-certified Go Cryptographic Module v1.0.0 (certificate #5247).
GOFIPS140: v1.0.0
run: |
set -euo pipefail
build_fips() {
goos="$1"; goarch="$2"; label="$3"; format="$4"
bin="./${{ matrix.path }}-fips_${goos}_${goarch}"
env CGO_ENABLED=0 GOOS="$goos" GOARCH="$goarch" go build ${{ env.BUILD_ARGS }} -tags fips140 -o "$bin" ./${{ matrix.path }}/main.go
# The toolchain adds fips140v1.0 only when GOFIPS140 is set, so both
# tags together prove the binary built as the FIPS variant.
go version -m "$bin" | grep -q -- '-tags=fips140,fips140v1.0' \
|| { echo "::error::$bin is not a FIPS 140-3 build"; exit 1; }
archive="${{ matrix.path }}-fips_${{ env.VERSION_NO_PREFIX }}_${label}"
if [ "$format" = tar ]; then
tar -cvzf "${archive}.tar.gz" "$bin" ./LICENSE ./CHANGELOG.md ./README.md ./sbom.xml
else
zip -r "${archive}.zip" "$bin" ./LICENSE ./CHANGELOG.md ./README.md ./sbom.xml
fi
}
build_fips darwin arm64 Darwin_arm64 tar
build_fips darwin amd64 Darwin_x86_64 tar
build_fips linux arm64 Linux_arm64 tar
build_fips linux amd64 Linux_x86_64 tar
build_fips windows amd64 Windows_x86_64 zip
# Bundle release artifacts
- name: Bundle release assets
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
Expand Down
20 changes: 20 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
version: "2"
linters:
enable:
- depguard
settings:
funlen:
statements: 50
depguard:
rules:
# These sit outside the FIPS 140-3 validated module boundary.
# See docs/reference/fips-140-3.md.
fips-140-3:
files:
- "!$test"
deny:
- pkg: golang.org/x/crypto
desc: use the stdlib crypto/* equivalent so the call routes through the validated Go Cryptographic Module
- pkg: crypto/md5
desc: MD5 is not an approved algorithm and is not part of the validated module
- pkg: crypto/sha1
desc: SHA-1 is not an approved algorithm and is not part of the validated module
- pkg: crypto/des
desc: DES/3DES is not an approved algorithm
- pkg: crypto/rc4
desc: RC4 is not an approved algorithm
exclusions:
generated: lax
presets:
Expand Down
31 changes: 0 additions & 31 deletions .goreleaser.yaml

This file was deleted.

37 changes: 35 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ PREFIX=/usr/local
PUBLIC_JSON_SCHEMA_DIR=docs/schema/v0/
ALL_GO_MOD_DIRS := $(shell find . -path ./test/integration -prune -o -type f -name 'go.mod' -exec dirname {} \; | sort)

# The FIPS variant builds against the CMVP-certified Go Cryptographic Module
# v1.0.0 (certificate #5247). The literal version is required; the
# "certified"/"inprocess" aliases vary by toolchain. The fips140 tag makes the
# binary require that module at startup rather than merely report on it.
FIPS_ENV := GOFIPS140=v1.0.0 CGO_ENABLED=0
FIPS_TAGS := fips140

FLAGD_DEV_NAMESPACE ?= flagd-dev
ZD_TEST_NAMESPACE_FLAGD_PROXY ?= flagd-proxy-zd-test
ZD_TEST_NAMESPACE ?= flagd-zd-test
Expand Down Expand Up @@ -39,6 +46,11 @@ build: workspace-init # default to flagd
make build-flagd
build-flagd:
go build -ldflags "-X main.version=dev -X main.commit=$$(git rev-parse --short HEAD) -X main.date=$$(date +%FT%TZ)" -o ./bin/flagd ./flagd

.PHONY: build-flagd-fips
build-flagd-fips:
$(FIPS_ENV) go build -tags $(FIPS_TAGS) -ldflags "-X main.version=dev -X main.commit=$$(git rev-parse --short HEAD) -X main.date=$$(date +%FT%TZ)" -o ./bin/flagd-fips ./flagd
go version -m ./bin/flagd-fips | grep -E 'GOFIPS140=|-tags='
.PHONY: test
test: test-core test-flagd test-flagd-proxy
test-core:
Expand All @@ -47,6 +59,27 @@ test-flagd:
go test -race -covermode=atomic -cover -short ./flagd/pkg/... -coverprofile=flagd-coverage.out
test-flagd-proxy:
go test -race -covermode=atomic -cover -short ./flagd-proxy/pkg/... -coverprofile=flagd-proxy-coverage.out
# fips140=only makes non-approved algorithms error or panic, so this fails if a
# tested path reaches MD5, SHA-1, RC4, 3DES or ChaCha20-Poly1305. Test mode only;
# released binaries run with fips140=on.
#
# -exec applies the GODEBUG to the test binaries only. Setting it in the
# environment would also apply it to the go command, whose module fetches over
# TLS negotiate X25519 and fail under fips140=only.
.PHONY: test-fips
test-fips:
$(FIPS_ENV) go test -tags $(FIPS_TAGS) -short -count=1 -exec 'env GODEBUG=fips140=only' ./core/... ./flagd/... ./flagd-proxy/...

# Regenerate the crypto dependency closure recorded in the FIPS docs. Pinned to
# linux/amd64: the closure is platform-dependent, so an unpinned run would
# differ between a developer machine and CI.
.PHONY: fips-closure
fips-closure:
@$(FIPS_ENV) GOOS=linux GOARCH=amd64 go list -tags $(FIPS_TAGS) -deps ./flagd ./flagd-proxy \
| grep -E '^(crypto|golang\.org/x/crypto)($$|/)|/crypto($$|/)' \
| sort -u > docs/reference/fips-crypto-closure.txt
@echo "wrote docs/reference/fips-crypto-closure.txt"

flagd-benchmark-test:
go test -bench=Bench -short -benchtime=5s -benchmem ./core/... | tee benchmark.txt
flagd-integration-test-harness:
Expand Down Expand Up @@ -74,10 +107,10 @@ uninstall:
rm /etc/systemd/system/flagd.service
rm -f $(DESTDIR)$(PREFIX)/bin/flagd
lint:
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.13.2
$(foreach module, $(ALL_GO_MOD_DIRS), ${GOPATH}/bin/golangci-lint run $(module)/...;)
lint-fix:
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.13.2
$(foreach module, $(ALL_GO_MOD_DIRS), ${GOPATH}/bin/golangci-lint run --fix $(module)/...;)
install-mockgen:
go install go.uber.org/mock/mockgen@v0.4.0
Expand Down
4 changes: 2 additions & 2 deletions core/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/open-feature/flagd/core

go 1.25.0
go 1.26.0

require (
buf.build/gen/go/open-feature/flagd/grpc/go v1.6.1-20260217192757-1388a552fc3c.1
Expand Down Expand Up @@ -29,7 +29,6 @@ require (
go.uber.org/mock v0.5.2
go.uber.org/zap v1.27.0
gocloud.dev v0.42.0
golang.org/x/crypto v0.52.0
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
golang.org/x/mod v0.35.0
golang.org/x/oauth2 v0.36.0
Expand Down Expand Up @@ -148,6 +147,7 @@ require (
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.52.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/term v0.43.0 // indirect
Expand Down
Loading
Loading