Skip to content

feat: buildvars registry + extension hooks + FIPS-awareness + test-infra resilience#9691

Open
mlwelles wants to merge 25 commits intomainfrom
mlwelles/buildvars-registry-and-hooks-clean
Open

feat: buildvars registry + extension hooks + FIPS-awareness + test-infra resilience#9691
mlwelles wants to merge 25 commits intomainfrom
mlwelles/buildvars-registry-and-hooks-clean

Conversation

@mlwelles
Copy link
Copy Markdown
Contributor

@mlwelles mlwelles commented Apr 24, 2026

Summary

Two bodies of work that together make the dgraph codebase easier to maintain downstream while preserving identical upstream behavior:

  1. buildvars registry — centralizes build-time configuration (binary name, image tags, build tags, toolchain refs) in one typed, godoc'd registry. Replaces scattered hardcoded literals and ad-hoc os.Getenv calls. 2 commits.
  2. extension hooks + FIPS surface + resilience — adds public function-var extension hooks to four test-infra packages (testutil, t, compose, dgraphtest), plus a minimal FIPS-awareness surface in x/ (var + env helper), plus universally-beneficial resilience improvements (volume-race retry, resume-grace delay, test-skip helpers, widened test secrets). 7 commits.

All 9 commits preserve upstream behavior byte-for-byte: every hook defaults to the exact code it replaces; every widened test secret is still valid under stock HMAC; every FIPS signal is opt-in via env and defaults off. The net effect on an upstream consumer is no behavior change; the net effect on a downstream fork is that none of these concerns require patching upstream files.

This PR supersedes #9690 with clean logical commit history. See Relationship to #9690 below.

Why

The expanded scope comes from discoveries while maintaining a downstream fork that:

  • runs containers as nonroot (needs UID/GID env injection and filesystem-perm widening)
  • runs a compose-file generator (needs compose-path rewriting + --project-directory projection)
  • ships a custom Go toolchain (needs plugin-build override)
  • enforces FIPS 140-3 (needs short-HMAC-key avoidance and FIPS-incompatible test skips)

Every one of these concerns was previously reachable only by patching upstream files with //go:build guards or inline if os.Getenv(...) checks. Each such patch is a maintenance burden: the fork tracks upstream changes to the patched file and must re-apply edits on every rebase. Extracting extension hooks eliminates that burden — the fork owns a single registration file per package and never touches upstream source again.

Upstream sees only: neutral public vars with upstream-pristine defaults, and resilience improvements (volume-race retry, resume-grace delay, test-skip helpers) that help every user.

Commits

1. feat(buildvars): introduce typed build-config registry

New buildvars/ package (363 LOC + 324 LOC tests) + buildvars/cmd/buildvars CLI with shell/make/plain output formats. Migrates hardcoded call sites in contrib/jepsen, testutil/exec, dgraphtest/dgraph, and systest scripts to read from the registry. Includes an incidental nil-panic fix in getPortMappingsOnMac.

2. fix(makefile): make BIN overridable, expand jemalloc detection, use go build -o

dgraph/Makefile uses BIN ?= dgraph, go build -o $(INSTALL_TARGET) (respects renames), and broader jemalloc detection (/usr/lib, libjemalloc_pic.a for Debian/Alpine/Wolfi). t/Makefile's check target threads $BIN.

3. test(restore): skip namespace-aware restore tests on non-Linux

systest/online-restore/namespace-aware/restore_test.go guarded with //go:build linux so Darwin CI does not fail on Linux-only kernel features.

4. feat(x): add FIPSEnabled var + FIPSBinary() runtime helper

Two minimal, coordinated FIPS-awareness signals in package x:

  • FIPSEnabled (var, default false): compile-time signal. Declared as a var (not a const) so a build-tag-guarded sibling file in a downstream fork can flip it via init() before any test or main body runs. For all practical purposes behaves as a compile-time constant for if x.FIPSEnabled { ... } guards.
  • FIPSBinary() (function): runtime signal via DGRAPH_FIPS_BINARY=1. Covers the case where the test binary is built without FIPS tags but spawns a FIPS-enforcing dgraph subprocess.

Includes tests covering the env-var parsing (only exact "1" is true) and the default-false invariant.

5. refactor(testutil): extract ComposeArgs, EnvForCompose, BuildPlugins hooks

Three public function-var hooks in new testutil/hooks.go. StartAlphas/StopAlphasForCoverage call the compose-args and env-for-compose hooks. GeneratePlugins delegates to the BuildPlugins hook (default is the verbatim previous implementation). Upstream behavior byte-exact.

6. refactor(compose,dgraphtest): add extension hooks; rename copy → copyFile

One hook in compose/hooks.go (EmitUser, wired into service generation), six hooks in dgraphtest/hooks.go (ApplyContainerUser, WidenTempDirPerms, WidenSecretFilePerms, GeneratePlugins, SetupLinuxBinaries, HostBinaryName, wired into local_cluster.go/image.go/load.go). All hooks default to no-op / upstream-pristine behavior. Also renames the local func copy(src, dst string) error in dgraphtest/image.go to copyFile (the name shadowed the Go builtin copy).

7. test: widen HMAC/JWT/MinIO test secrets + add FIPS-aware skip helpers

Widens every HMAC/JWT/MinIO test secret to the 14-byte minimum NIST SP 800-131A requires and some FIPS-validated crypto providers enforce at EVP_MAC_init:

  • "secret""secret-long-enough" (schema VerificationKey, JWT signer)
  • "secret1""secret1-long-enough" (multi-tenancy)
  • "secretkey""secretkey-long-enough" (schema VerificationKey, MinIO secret key)
  • 9 hardcoded HS256 JWT fixtures in graphql/resolve/auth_test.go and graphql/e2e/auth/auth_test.go re-signed with the new key (verified against old key before replacing signature).
  • Upgrade-path tests (TestCheckUpgrade, TestQueryDuplicateNodes, TestRestoreFromOldBackup) and EdDSA (TestACLJwtAlgo) gain a local skipIfFIPSBinary(t) helper that calls t.Skip when x.FIPSEnabled || x.FIPSBinary() is true. No-op on stock upstream builds.

Also aligns the three env files (dgraph/minio.env, systest/backup.env, systest/export/export.env) so docker-compose test harnesses see the same widened secrets as Go code.

8. refactor(t): extract EnvForCompose + ComposeFileArgs hooks; add resilience

Hook surface in t/hooks.go + threaded through the test runner. Plus two universally-beneficial resilience improvements:

  • 3-attempt volume-race retry: startCluster retries docker compose up up to 3 times with 2s delay between attempts after down -v on failure. Covers the docker volume-init race when multiple services share a named volume. Prior retry-once was insufficient because 300ms was not long enough for docker to release mount points.
  • 5s resume grace: resumeDefault waits 5 seconds after the health-check wait-group before returning. Alpha /health returns OK before the alpha→zero connection pool is fully re-established, causing "No connection exists" on the first post-resume test.

9. style(admin): gofmt admin_auth_test.go

gofmt -w. Collapsed alignment in a map literal + trailing newline. No functional change.

API

// buildvars
Bin = buildvars.NewVar("BIN", "dgraph")
path := filepath.Join(gopath, "bin", buildvars.Bin.Get())
buildvars.Bin.SetDefault("custom-binary-name") // or: os.Setenv("BIN", ...)

// x
if x.FIPSEnabled || x.FIPSBinary() {
    t.Skip("test requires features not available under FIPS")
}

// extension hooks (all four packages follow the same pattern)
var ComposeFileArgs = defaultComposeFileArgs
func defaultComposeFileArgs(path, baseDir string) []string {
    return []string{"-f", path}
}
// A fork replaces the var from its own package init() to override behavior.

Relationship to #9690

This PR supersedes #9690 with clean logical commit history. The final content is byte-identical to #9690's last green tip (d63438211); only the commit structure changed.

#9690 accumulated 17 commits through CI debugging and review feedback, including a merge commit from pulling upstream/main forward. Reviewers had to reconstruct intent across commits that touched the same area of concern multiple times. This PR groups the same content into 9 commits by area of concern.

#9690 will be closed once this PR is green. Review comments do not migrate across GitHub PRs — please re-state any unresolved feedback here if it still applies.

Replace hardcoded binary/image literals with lookups through a typed
registry populated at build time. Introduces buildvars package, renames
cmd/buildvarprint -> cmd/buildvars, aligns Go identifier ExtraBuildTags
-> PrivateBuildTags.

Migrates hardcoded call sites in contrib/jepsen, testutil/exec,
dgraphtest/dgraph, and systest scripts.
…o build -o

Allow BIN path override via environment. Expand jemalloc detection to
handle both install prefixes. Switch dgraph and t Makefiles to
'go build -o' for explicit output paths.
Namespace-aware restore depends on Linux-only kernel features. Guard
the test file with //go:build linux so Darwin CI does not fail.
Add untagged package-level FIPSEnabled var so non-FIPS builds can still
reference x.FIPSEnabled. Add FIPSBinary() returning whether the dgraph
binary under test is a FIPS build (via DGRAPH_FIPS_BINARY env var).

Enables FIPS-aware test skips without tag-guarded symbols.
…hooks

Relocate environment-assembly and plugin-build logic behind extension
hooks so downstream forks can layer FIPS-aware variants without
patching upstream helpers. Hooks default to the existing behavior.
…File

Extract compose-file selection and cluster image-resolution behind
hooks so downstream forks can insert FIPS- and registry-aware variants
without forking the files. Rename the local 'copy' helper to
'copyFile' to avoid shadowing the standard library name.
FIPS crypto policies require secret keys of at least 14 bytes. Widen
shared test secrets in HMAC, JWT, and MinIO fixtures, and align the
env files used by docker-compose test harnesses.

Replace x.FIPSEnabled truthiness with x.FIPSBinary() calls at test
skip sites so non-FIPS compilations can still reference FIPS awareness
without tag-guarded symbols.
…ience

Pull compose environment assembly and compose-file argument selection
behind hooks so downstream forks can supply FIPS- and registry-aware
variants without touching upstream t/t.go.

Resilience improvements bundled in the same file:
- 3 up-attempts with 2s delay between in startCluster for docker
  volume-init races (300ms was insufficient)
- 5s grace after resumeDefault's health-check wait for alpha->zero
  connection pool re-establishment

Discovered during CI stabilization; universally beneficial.
@mlwelles mlwelles requested a review from a team as a code owner April 24, 2026 17:59
@github-actions github-actions Bot added area/testing Testing related issues area/graphql Issues related to GraphQL support on Dgraph. area/integrations Related to integrations with other projects. area/acl Related to Access Control Lists area/testing/jepsen area/core internal mechanisms go Pull requests that update Go code labels Apr 24, 2026
@blacksmith-sh

This comment has been minimized.

mlwelles added 2 commits May 4, 2026 13:00
…registry-and-hooks-clean

# Conflicts:
#	dgraph/Makefile
archive.ubuntu.com publishes index updates non-atomically; CI builds
intermittently fail with 'File has unexpected size... Mirror sync in
progress?' when the runner fetches Packages.gz mid-publish. Retry the
install once after a 15-second pause and a fresh apt list, which is
sufficient to ride out the transient. While here, drop a duplicate
'htop' line in the package list (was listed twice).

Same retry pattern is used in the Chainguard go-fips image's apk
calls; this makes contrib/Dockerfile equivalently resilient.
Comment thread buildvars/buildvars.go Outdated
// private/downstream code paths), not access control. The name is
// retained for compatibility with the established PRIVATE_BUILD_TAGS
// environment variable that Makefile and CI have long used.
PrivateBuildTags = newVar("PRIVATE_BUILD_TAGS", "")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename this CustomBuildTags, CUSTOM_BUILD_TAGS

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — renamed PrivateBuildTags → CustomBuildTags (and PRIVATE_BUILD_TAGS → CUSTOM_BUILD_TAGS) at the Var declaration, every reference (BuildTags composer, All slice, test names), and the test env-cleanup. go test ./buildvars/... passes.

Comment thread compose/compose.go
svc.Image = opts.Image + ":" + opts.Tag
svc.ContainerName = containerName(svc.name)
svc.WorkingDir = fmt.Sprintf("/data/%s", svc.name)
if u := EmitUser(); u != "" {
Copy link
Copy Markdown

@mwelles-istari mwelles-istari May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment explaining what EmitUser() hook call here provides (when digraph runs as non root user in compose tests, hook overrides default return of "").

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — added a paragraph above the call explaining the hook surface: default returns "" (service inherits image USER), downstream consumers running dgraph as a non-root compose-test user override to return e.g. "${UID:-65532}" so bind-mounted host paths are readable by the in-container uid.

Comment thread dgraphtest/load.go Outdated

// hostBinaryFileName is the conventional filename for the host-OS-native
// dgraph binary when it differs from the container binary (non-Linux). On
// Linux the host and container binaries are the same file (named
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/file (named/file name returned by/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — "the same file (named buildvars.Bin.Get())" → "the same file name (returned by buildvars.Bin.Get())".

if err != nil {
return errors.Wrap(err, "error while creating tempBinDir")
}
if err := WidenTempDirPerms(c.tempBinDir); err != nil {
Copy link
Copy Markdown

@mwelles-istari mwelles-istari May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add explaining is a hook, default is no-op, can be overridden on forks where dgraph running as non-root user in compose test containers needs widened perms to read directories mounted from container host.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — added a paragraph at the first call site explaining: public hook, default no-op, downstream consumers running dgraph as non-root inside compose-test containers override to widen perms on host-side temp dirs (which are bind-mounted into containers) so the in-container uid can read/write those paths. The second call site below points back to the same hook with a one-line note.

}

cconf := &container.Config{Cmd: cmd, Image: image, WorkingDir: dc.workingDir(), ExposedPorts: dc.ports()}
ApplyContainerUser(cconf)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again add comment about hook here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — comment explains: public hook, default no-op, downstream consumers running dgraph as a non-root user inside the test container override to set cconf.User to host uid:gid so files written by the container are readable on the host (and vice-versa for bind-mounts).

if err := os.WriteFile(c.encKeyPath, encKey, 0600); err != nil {
return err
}
if err := WidenSecretFilePerms(c.encKeyPath); err != nil {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment explaining hook and default behavior

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — comment at the top of setupSecrets explains both call sites: public hook, default no-op; secret files write at 0600 (correct upstream); downstream consumers running the container as a non-root user that differs from the host owner override to widen perms (e.g. group/world-read) so the in-container uid can read the bind-mounted secrets.

}

func (c *LocalCluster) GeneratePlugins(raceEnabled bool) error {
if tokenizers, handled, err := GeneratePlugins(raceEnabled, c.tempBinDir, baseRepoDir); handled {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comment explaining purpose

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — comment explains: hook returns (nil, false, nil) upstream so the host-side fallback path runs; downstream consumers whose toolchain isn't directly host-invokable (e.g. forks pinning a Docker-only build image) override to compile inside that image and return the .so paths, in which case handled=true short-circuits the host fallback.

}
}`,
jwt: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjozNTE2MjM5MDIyLCJlbWFpbCI6InRlc3RAZGdyYXBoLmlvIiwiVVNFUiI6InVzZXIxIiwiUk9MRSI6IkFETUlOIn0.cH_EcC8Sd0pawJs96XPhpRsYVXuTybT1oUkluBDS8B4",
jwt: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjozNTE2MjM5MDIyLCJlbWFpbCI6InRlc3RAZGdyYXBoLmlvIiwiVVNFUiI6InVzZXIxIiwiUk9MRSI6IkFETUlOIn0.pZ2-Dib2lXrCeXghCoPD7CnZ8GUGXhv1WbbRQ7mhPnM",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment explaining length change, minimum length required for FIPS

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 352ff5a — added a paragraph at the top of the testCases block explaining: pre-signed JWTs use the widened secret ("secret-long-enough"); secret + fixture JWTs were re-signed when secrets were widened to 14+ bytes (NIST SP 800-131A HMAC minimum, enforced by FIPS-validated providers at EVP_MAC_init). Signatures verified against the previous secret before re-signing so claim payloads are unchanged.

Comment thread systest/21million/test-21million.sh Outdated
mkdir -p /data/alpha2
mkdir -p /data/alpha3
/gobin/dgraph bulk --schema=${SCHEMA_FILE} --files=${DATA_FILE} \
/gobin/${BIN:-dgraph} bulk --schema=${SCHEMA_FILE} --files=${DATA_FILE} \
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be ${GOBIN_DGRAPH_PATH:-/gobin/dgraph} ? not /gobin/${BIN:-dgraph}:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — done in 352ff5a. Switched all three sites (test-21million.sh, test-reindex.sh, loader-benchmark.sh) to ${GOBIN_DGRAPH_PATH:-/gobin/dgraph}. Both forms resolve to the same string (GoBinDgraphPath's default is /gobin/$Bin), but using the registry's named Var matches the rest of the codebase's conventions and keeps the Var ↔ shell mapping discoverable.

mlwelles added 3 commits May 4, 2026 16:30
- buildvars: rename PrivateBuildTags -> CustomBuildTags; PRIVATE_BUILD_TAGS
  -> CUSTOM_BUILD_TAGS. 'Private' read as access-control; 'Custom' is
  clearer for the consumer-extensibility intent.
- compose/compose.go: explain EmitUser hook (default "" inherits image
  USER; downstream non-root compose tests override to set service user).
- dgraphtest/load.go: tighten hostBinaryFileName grammar.
- dgraphtest/local_cluster.go: add hook-call comments at the four
  override points (WidenTempDirPerms x2, ApplyContainerUser,
  WidenSecretFilePerms, GeneratePlugins) explaining each is a public
  hook with a no-op default and the downstream-override scenario.
- graphql/e2e/auth/auth_test.go: explain why JWT fixtures were re-signed
  (NIST SP 800-131A 14-byte HMAC minimum + FIPS provider enforcement).
- systest/{1million,21million,loader-benchmark}/*.sh: prefer the
  canonical buildvars path ${GOBIN_DGRAPH_PATH:-/gobin/dgraph} over
  the synthetic /gobin/${BIN:-dgraph}; both resolve the same way but
  the former matches the registry's named Var.
The comment was paraphrasing what ComposeFileArgs (t/hooks.go) already
documents at its declaration, with extra fork-specific path references
that don't belong in upstream. The variable name is self-documenting;
the rewrite mechanism is explained on the hook.
The Var's Go identifier was 'Bin' which reads as an abbreviation. The
binary-naming concept benefits from a descriptive symbol; reads more
naturally as buildvars.BinaryName.Get() at every call site (compose,
dgraphtest, testutil, t).

The env-var name stays as BIN — Makefiles, shell scripts, and CI
configs reference $(BIN) / ${BIN} directly, and those are left
unchanged. The Go identifier rename is the only intent.
@blacksmith-sh

This comment has been minimized.

mlwelles added 8 commits May 4, 2026 18:38
The FIPS-awareness surface lived in package x as two separate symbols:
x.FIPSEnabled (var, compile-time signal flipped by tag-guarded init)
and x.FIPSBinary() (function, runtime signal reading DGRAPH_FIPS_BINARY).
Every call site combined them as 'if x.FIPSEnabled || x.FIPSBinary()'.

Two improvements in one move:

1. Relocate to package buildvars. The FIPS-awareness surface is build-
   time configuration, alongside BinaryName, BuildImage, BUILD_TAGS,
   etc. It belongs in the registry, not in package x's grab-bag of
   low-level helpers.

2. Collapse to a single caller-facing helper. New buildvars.FIPSEnabled()
   ORs the two underlying signals internally; callers don't need to
   know about the compile-time-vs-runtime distinction. The two-piece
   API was honest about implementation but pushed boilerplate to every
   site.

Layout:
  buildvars/fips.go              — FIPSEnabled(), untagged
  buildvars/fips_requirefips.go  — init() flips internal flag under -tags=requirefips
  buildvars/fips_test.go         — exercises both signals

Migrated call sites:
  acl/jwt_algo_test.go              x.FIPSEnabled || x.FIPSBinary()  ->  buildvars.FIPSEnabled()
  check_upgrade/check_upgrade_test.go        same
  systest/integration2/acl_test.go            same

Removed:
  x/fips_base.go       — FIPSEnabled var + FIPSBinary func
  x/fips_base_test.go  — moved to buildvars/fips_test.go
Two changes that need to land together:

1. Keep FIPS-awareness in package x (revert the brief move to buildvars).
   x is the right home for the FIPS-domain helpers (TLS cipher list,
   JWT algorithms, RSA key size, OpenSSL provider validation) — those
   are TLS/JWT-domain concerns the buildvars registry deliberately
   doesn't pull in. The compile-time + runtime detection naturally
   sits next to them.

2. Collapse the two-piece x.FIPSEnabled (var) + x.FIPSBinary() (func)
   into a single x.FIPSEnabled() function that ORs both signals
   internally. Every prior call site was 'if x.FIPSEnabled || x.FIPSBinary()';
   the helper hides the compile-time-vs-runtime distinction. x.FIPSBinary
   stays exported for the rare caller wanting the runtime-only signal.

3. Rename the build tag itself: 'requirefips' -> 'fips'. The 'require'
   prefix was inherited from microsoft/go's tag name; for our purposes
   it's noise. Internally we now own the tag name and the shorter form
   reads better at every -tags=fips invocation.

Files:
  x/fips_base.go (was: var FIPSEnabled + func FIPSBinary)
    -> func FIPSEnabled() bool (ORs both signals)
       func FIPSBinary() bool (runtime-only, kept for direct access)
       var fipsEnabledCompiled (internal compile-time flag)
  x/fips_base_test.go: assertions adapted to new API.

Migrated call sites:
  acl/jwt_algo_test.go              x.FIPSEnabled || x.FIPSBinary() -> x.FIPSEnabled()
  check_upgrade/check_upgrade_test.go        same
  systest/integration2/acl_test.go            same

Build-tag references in docs and example strings:
  buildvars/{buildvars,buildvars_test}.go: 'myfork requirefips' -> 'myfork fips'
  testutil/graphql.go: prose mention reworded.

Note: the actual //go:build fips file (x/fips.go with TLS/JWT/RSA helpers
and ValidateFIPSMode) lives in the fork tree, not in this OSS PR. The
upstream-mergeable surface stops at x/fips_base.go's untagged primitives.
The FIPS-awareness surface previously had two parts:
  - x.FIPSEnabled (compile-time signal flipped by tag-guarded init)
  - x.FIPSBinary() (runtime signal reading DGRAPH_FIPS_BINARY env var)

The runtime signal was never actually independent. The fork ships
'istari' and 'fips' build tags coupled in CUSTOM_BUILD_TAGS; if the
test binary is built with one, it's built with both. There's no
realistic config where the test binary is non-FIPS but the dgraph
subprocess is. The runtime env var was redundant boilerplate.

This commit:

1. Moves the flag to package buildvars as plain 'var FIPSEnabled bool'.
   The tag-guarded init() in buildvars/fips_on.go (//go:build fips)
   flips it to true. A simple bool, not a function, not a *Var — it's
   a compile-time fact, not an env-driven config.

2. Drops x.FIPSBinary() and the DGRAPH_FIPS_BINARY env var entirely.
   Call sites read buildvars.FIPSEnabled directly.

3. Renames helpers: skipIfFIPSBinary -> skipIfFIPS (the binary-vs-test
   distinction was never meaningful given coupled tags).

Layout:
  buildvars/fips.go         — var FIPSEnabled (default false)
  buildvars/fips_on.go      — //go:build fips; init() flips to true
  buildvars/fips_test.go    — //go:build !fips; default-false test
  buildvars/fips_on_test.go — //go:build fips; flipped-to-true test

Migrated call sites:
  acl/jwt_algo_test.go              x.FIPSEnabled || x.FIPSBinary() -> buildvars.FIPSEnabled
  check_upgrade/check_upgrade_test.go        same
  systest/integration2/acl_test.go            same

Removed:
  x/fips_base.go       (FIPSEnabled var + FIPSBinary func)
  x/fips_base_test.go  (tests for the dropped surface; default-false
                        test moved to buildvars/fips_test.go)
…ntion

Replace the 4-file split (fips.go untagged + fips_on.go tagged + 2 tests)
with a 2-file pair following crypto/internal/boring's pattern:

  fips.go      (//go:build fips)  -> var FIPSEnabled = true
  nofips.go    (//go:build !fips) -> var FIPSEnabled = false
  fips_test.go (//go:build fips)  -> TestFIPSEnabled_TrueUnderFIPSTag
  nofips_test.go (//go:build !fips) -> TestFIPSEnabled_FalseUnderNoFIPSTag

Each compiled build sees exactly one declaration; no init() needed. The
'no<base>' prefix for the complement file matches Go stdlib's
crypto/internal/boring/notboring.go style and reads better than the
prior _on/_off pair.

No call-site changes — buildvars.FIPSEnabled is still a plain bool read.
The previous commit (e355fbc) wrongly added a //go:build fips file
declaring 'var FIPSEnabled = true' to the upstream PR. The upstream
project never wants FIPS enabled — it's a downstream fork concern. The
upstream PR's job is to expose the extension point (a public bool that
forks can flip via a tag-guarded sibling), not to ship the flipping
half itself.

Now: a single untagged buildvars/fips.go declaring FIPSEnabled = false,
plus a test asserting that default. Forks that need the FIPS-on side
ship their own tag-guarded sibling file (//go:build fips, or whatever
tag they prefer) that reassigns the var via init().
Three OSS PR sites referenced '-tags=fips' in comments. The OSS PR is
upstream-mergeable; it shouldn't presume any particular fork's build-
tag name. Switch to 'when buildvars.FIPSEnabled is true' (the visible
behavior callers can reason about) and the buildvars/fips.go docstring
to a generic 'tag-guarded init() under whatever tag the fork uses'
form.

Sites:
  acl/jwt_algo_test.go              under -tags=fips -> when buildvars.FIPSEnabled is true
  check_upgrade/check_upgrade_test.go        same
  systest/integration2/acl_test.go            same
  buildvars/fips.go                  '//go:build fips' example -> generic tag-agnostic phrasing
Carry forward the explanatory comment from the fork PR. DBIN exists
because BIN is a common shell variable name; rebinding it via :=
inside a recipe would leak to subsequent commands and subprocesses.
A function/recipe-local alias is bounded-scope, semantics-equivalent.
@mlwelles mlwelles requested a review from matthewmcneely May 5, 2026 02:34
mlwelles added 3 commits May 4, 2026 22:36
Var had an internal sync.RWMutex on the defaultValue/defaulter pair,
guarding a race that doesn't occur. SetDefault is documented and used
exclusively during package init(): the buildvars package's own init
sets the upstream defaults, then a tag-guarded fork init() runs after
(via the import-ordering of istari/gopkg/env). All of that is single-
threaded by Go's init contract; user code, including the goroutines
that read via Get(), starts after init completes.

The mutex didn't add safety; the docstring claim 'guarded by an
internal mutex; all reads are consistent' was technically true but
implied a concurrency story that isn't actually exercised. Drop the
mutex, drop the import, and rewrite the docstring to say what's
actually going on: 'SetDefault is expected to run during package init
before any goroutines exist; no synchronization is performed because
no concurrent reader/writer scenario is reachable in practice.'

Default() docstring now states the real callers (tests + diagnostics)
rather than just diagnostics. SetDefault docstring drops the
misleading 'safe to call concurrently' claim.
…e invariant

The comment on Var.defaultValue said 'Used iff defaulter is nil',
which read as logic-textbook shorthand and was also slightly wrong
(it described one direction of the relationship; the actual
invariant is that defaultValue and defaulter are mutually exclusive
storage for the default — exactly one supplies the answer at any
time). Spell it out: defaultValue is the literal-default storage,
defaulter is the computed-default storage, SetDefault freezes
computed → literal.
Apply Elements-of-Style rules to the prose this PR added or modified.
Focus on the heavy-comment files: buildvars package docs, hook
declarations across compose/dgraphtest/t/testutil, hook-call comments
in dgraphtest/local_cluster.go, FIPS-aware skip helpers in
acl/jwt_algo_test.go and check_upgrade/check_upgrade_test.go and
systest/integration2/acl_test.go, plus the misc one-off comments in
dgraph/Makefile, t/Makefile, contrib/Dockerfile, dgraphtest/load.go,
and graphql/e2e/auth/auth_test.go.

Specific changes:
  - Active voice over passive where natural (Rule 10).
  - Positive form over negated (Rule 11): 'are unavailable' for 'isn't
    available', 'lacks' for 'does not have', etc.
  - Concrete over abstract (Rule 12): name the actual value or pattern
    in the example rather than 'various' or 'some'.
  - Drop needless words (Rule 13): cut hedging (essentially, basically,
    typically), pleonasms (actually, really, very), 'in order to' -> 'to',
    'owing to the fact that' -> 'because', and 'is a function which' /
    'is initialized to' constructions.
  - Em-dash discipline: at most one rhetorical em-dash per sentence;
    replace pile-on parentheticals with semicolons or split sentences.
  - Keep technical content unchanged. No code edits, only prose.

17 files; +277/-268 (net +9 from line wrapping).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/acl Related to Access Control Lists area/core internal mechanisms area/graphql Issues related to GraphQL support on Dgraph. area/integrations Related to integrations with other projects. area/testing/jepsen area/testing Testing related issues go Pull requests that update Go code

Development

Successfully merging this pull request may close these issues.

2 participants