# Hermetic Build Audit > Audit one Bazel workspace's build configuration - will two machines given the same commit build the same bytes, and share the cache - then fix it. The free check runs in the browser and uploads nothing: it reads the pasted .bazelversion, .bazelrc (and other rc files), MODULE.bazel, WORKSPACE, BUILD and .bzl files, lexes the Starlark so strings and comments are never mistaken for calls, reads every top-level call with its attributes and every rc line with its command, config and flags, follows --config chains, and runs 21 deterministic checks drawn from Bazel build practice. The paid audit rates hermeticity, caching, the build graph and the configuration, confirms or dismisses every flag and gives exact before/after edits per finding; the paid fix lane writes the whole fixed file(s) and a changes list tied to the flags. The page checks every quote and line against the paste, applies every edit and file back into the paste and re-runs its checks - including that every target, repository and named config is still there and that no file was added - and calls out a reply that repeats a credential from the paste. App: https://hermetic-build-audit.skillsafe.ai/ API tutorial: https://hermetic-build-audit.skillsafe.ai/api.html ## Input - The build files pasted into one box, each introduced by a `# file: ` line (`# file: .bazelrc`, `# file: MODULE.bazel`, `# file: apps/web/BUILD.bazel`); dropped files or a dropped workspace folder are joined that way automatically, and files that are not Bazel files are skipped. A paste with no `# file:` line is read as one file, named by what it looks like (MODULE.bazel, WORKSPACE.bazel, .bazelrc, .bazelversion or BUILD.bazel). - A target's package is the directory of its BUILD file, so `apps/web/BUILD.bazel` defines `//apps/web:`. - rc lines are read with their command (`build`, `test`, `common` ...), config (`build:ci`), flags (`--name=value`, `--name value`, `--noname`), quotes and `\` continuations; `--config=X` chains are followed, so a flag that reaches every build through a config counts as on for every build. - Nothing is fetched, analysed or built: every flag is a reading of the text, with the file and line it points at. The remote cache, the CI runner, the machines and unpasted files are not visible: BZ-22 says so, and the note is where you give facts ("the tested commit is ...", "the cache also serves grpcs on 9092"). ## Flags the free check raises - BZ-01 (medium): no .bazelversion pasted next to a root MODULE.bazel, WORKSPACE or .bazelrc, or a value that is not an exact release (latest, 7.x, last_green). - BZ-02 (high): http_archive, http_file or http_jar (in WORKSPACE, MODULE.bazel via use_repo_rule, or a .bzl macro) with no sha256 or integrity, a sha256 that is not 64 hex digits ("..." included), a malformed integrity; archive_override with no integrity; ctx.download / download_and_extract with no sha256. - BZ-03 (high): git_repository, new_git_repository or git_override on a branch, or with neither commit nor tag (low: pinned by tag only). - BZ-04 (high): local_repository, new_local_repository or local_path_override at an absolute path. - BZ-05 (high): curl, wget, pip/npm/yarn/pnpm install, go get, git clone/fetch, apt or brew install, docker pull inside a genrule cmd or a run_shell command (medium: date, $RANDOM or uuidgen). - BZ-06 (medium): --spawn_strategy, --genrule_strategy or --strategy set to local or standalone (low when only under a named config nothing always pulls in); targets tagged no-sandbox or local; use_default_shell_env = True or no-sandbox/local execution_requirements in a .bzl action. - BZ-07 (medium): --action_env=NAME with no value (copied from the client); a remote cache or executor configured without --incompatible_strict_action_env on every build. - BZ-08 (medium): a remote cache on every build (directly or through --config) with local results uploaded (no --noremote_upload_local_results). - BZ-09 (medium): --remote_cache, --remote_executor, --bes_backend or --remote_downloader over http:// or grpc:// (localhost exempt). - BZ-10 (medium): --stamp on every build. - BZ-11 (medium): --nocache_test_results or --cache_test_results=no, or --runs_per_test above 1, for every test. - BZ-12 (medium): targets tagged no-cache, no-remote-cache or no-remote. - BZ-13 (medium): glob() in deps, runtime_deps, exports or implementation_deps. - BZ-14 (low): a root-package target whose srcs glob ** over the whole tree. - BZ-15 (low): package(default_visibility = ["//visibility:public"]). - BZ-16 (high): a --config value no rc line defines (low when an imported rc file was not pasted and may define it). - BZ-17 (medium): WORKSPACE declares external repositories or setup calls (high when .bazelversion is 8 or later and --enable_workspace is not set). - BZ-18 (high): a literal credential in --remote_header, --bes_header and the other header flags, a user:password in an endpoint URL, or a secret-named variable with a value in --action_env, --repo_env or --test_env. The value is masked as *** everywhere the page shows it. - BZ-19 (medium): --jobs of 64 or more on every build or in a config with no remote executor. - BZ-20 (low): --remote_timeout of ten minutes or more. - BZ-21 (low): --experimental_* flags on every build. - BZ-22 (info): context - counts, the Bazel version, what is outside the check. ## Free extras - Every external repository and bazel_dep with how it is pinned (checksum, placeholder, none, commit, tag, branch, path, version); every rc line by command and config; every target with its kind and tags; every file. - Put any audit finding (or all of them, or the fixed files) back into the paste and re-run the check; undo puts the original back. - Exports: the check as Markdown, the flags as CSV, the edited or fixed files, the findings or changes as CSV, the whole result as JSON. ## Paid lanes (the `task` field) - `audit`: `{task, verdict: blocked|needs_work|ready, headline, workspace, areas: [{area: hermetic|cache|graph|config, status: sound|fragile|broken, note}], findings: [{id, flags, file, line, severity, area, title, evidence, why, edits: [{before, after}]}], flag_answers: [{flag, status: confirmed|dismissed, reason}], plan, questions, summary}`. `before` is an exact slice of the file, applied in order. - `fix`: `{task, verdict: fixed|partial, headline, files: [{path, content}], changes: [{file, target, flags, change, why}], verify, open: [{item, flags, reason}], questions, summary}`. `content` is the whole file; `target` is a label or `(file)`; every target, repository and named config stays, and no file is added. - Run input: `{task, code, facts, note?, audit_handoff?, retry_note?}` - all strings; `facts` is the page's analysis as a JSON string. The audit hands its findings to the fix lane with every edit applied to `code`. - The model never invents a checksum, a commit, a registry version, an endpoint or a label: without one from the note or the paste the item is a question (audit) or left open (fix). - Model: gpt-terra, 10% publisher markup. A run needs a signed-in account; the reservation shown before a run is a hold, and only what the run uses is charged. ## Sources - bazel-build-optimization by Seth Hobson, wshobson/agents (github.com/wshobson/agents, plugins/developer-essentials/skills/bazel-build-optimization), MIT - https://skillsafe.ai/skill/@wshobson/bazel-build-optimization - The checks and the reconciliation are original to this app. Bazel is a trademark of Google LLC; this app is not affiliated with or endorsed by Google or the Bazel project.