Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
197 commits
Select commit Hold shift + click to select a range
973d0eb
docs: add ADR-006 FIPS password hashing (pre-review draft)
aaronlippold Jul 29, 2026
d98b269
docs: rewrite ADR-006 after adversarial review — verified sources only
aaronlippold Jul 29, 2026
35d47de
build: import RPM packaging from saf-packaging
aaronlippold Jul 30, 2026
381d00b
docs: restore NOTICE.md
aaronlippold Jul 30, 2026
9bfff1e
Revert "docs: restore NOTICE.md"
aaronlippold Jul 30, 2026
ac593eb
docs: bump LICENSE.md copyright to 2026
aaronlippold Jul 30, 2026
b6a1228
docs: use the MITRE SAF license for hdf-converters
aaronlippold Jul 30, 2026
7f11961
docs: normalize licensing across all monorepo workspaces
aaronlippold Jul 30, 2026
de204f7
chore: complete package.json metadata across workspaces
aaronlippold Jul 30, 2026
ff16bc2
fix: make the pack-time manifest rewrite crash-safe
aaronlippold Jul 30, 2026
cb40f42
docs: add SECURITY.md and CONTRIBUTING.md
aaronlippold Jul 30, 2026
3be0814
docs: revise ADR-006 — correct the FIPS-mode approach, add credential…
aaronlippold Jul 30, 2026
d2fca99
build: repair RPM build inputs after the move into this repo
aaronlippold Jul 30, 2026
7fb6156
build: resolve RPM version from the repository, not rpmspec
aaronlippold Jul 30, 2026
987bfff
ci: build RPMs for el8/el9 on x86_64 and aarch64, attach to releases
aaronlippold Jul 30, 2026
a8b1f1c
docs: add the distribution model to ADR-006
aaronlippold Jul 30, 2026
647536b
ci: bootstrap make alongside git in the RPM build container
aaronlippold Jul 30, 2026
ed3ff63
docs: fold in Will's review — correct module version, CLI claims, pre…
aaronlippold Jul 30, 2026
c1140e1
docs: settle ADR-006 open designs — KDF limiter, write-gate triggers,…
aaronlippold Aug 5, 2026
66a921d
feat: add OpenTofu module for FIPS-enabled RHEL 9 EC2 test host
aaronlippold Aug 6, 2026
404a550
docs: user-space session-manager-plugin install — brew cask needs blo…
aaronlippold Aug 6, 2026
5b38daa
docs: rebuild-proof SSH-over-SSM config — wildcard i-* + Name-tag alias
aaronlippold Aug 6, 2026
f7173af
feat: bake tmux into the test host — long jobs must survive SSM idle …
aaronlippold Aug 6, 2026
0e0675b
feat: idle auto-stop — CloudWatch alarm stops the box after 45 min be…
aaronlippold Aug 6, 2026
1691d36
feat: fips-box pause/wake/status — deliberate stop and ssh-ready wake
aaronlippold Aug 6, 2026
0c1f180
feat: single identity knob — TF_VAR_name drives tofu, fips-box, and t…
aaronlippold Aug 6, 2026
20674fc
research: FIPS-host spike findings — provider activates in-container,…
aaronlippold Aug 8, 2026
4de0e26
feat: add @heimdall/password-hash-vectors workspace with malformed-ha…
aaronlippold Aug 8, 2026
3dd3db9
feat: add known-good vectors + FORMAT_VERSION to @heimdall/password-h…
aaronlippold Aug 8, 2026
df31125
feat: add pure hashPassword with PHC encoding (apps/backend/src/crypt…
aaronlippold Aug 8, 2026
8e41ad2
fix: complete the Multer mock file in the evaluations controller spec
aaronlippold Aug 9, 2026
b6d6465
feat: add verifyPassword with the FIPS gate and a KDF concurrency lim…
aaronlippold Aug 9, 2026
f97b625
feat: add PasswordService and CryptoModule
aaronlippold Aug 9, 2026
7223795
feat: add compare-and-swap rehash writers and migrate the verify-only…
aaronlippold Aug 9, 2026
ac36c60
feat: migrate the login path to PBKDF2 verification with lazy rehash
aaronlippold Aug 9, 2026
ea22956
feat: hash the bootstrap administrator with PBKDF2
aaronlippold Aug 9, 2026
043a944
feat: add the §12 write gate, FIPS boot assertions, and marker migration
aaronlippold Aug 11, 2026
b13c4a7
feat: migrate remaining bcrypt sites to PasswordService
aaronlippold Aug 11, 2026
ebc5a78
feat: add §17 rehash audit logging and the lifecycle regression suite
aaronlippold Aug 11, 2026
caed841
feat: add the health/readiness surface and admin migration report
aaronlippold Aug 11, 2026
fb853b5
feat: harden RPM packaging for FIPS hosts
aaronlippold Aug 11, 2026
a669c00
chore: modernize the dev workflow — self-selecting start:dev, per-app…
aaronlippold Aug 11, 2026
84fcda6
fix: import CryptoModule in the evaluations spec harness
aaronlippold Aug 11, 2026
a790b7c
feat: wire health probes into compose and the RPM runbook
aaronlippold Aug 11, 2026
d29c2c5
fix: pin the Tailwind generator and guard its committed output
aaronlippold Aug 11, 2026
a1beccb
feat: scaffold the isolated VitePress documentation site
aaronlippold Aug 11, 2026
f12ff86
docs: separate internal records from the published docs tree
aaronlippold Aug 12, 2026
c2816ef
feat(docs): add canonical environment-variables reference
aaronlippold Aug 12, 2026
54dd1df
fix(auth): accept GITLAB_CLIENTSECRET for the GitLab client secret
aaronlippold Aug 12, 2026
41a9422
chore(lint): repair the lint configuration and adopt Prettier
aaronlippold Aug 12, 2026
3bdd1f1
style(backend): apply lint autofixes and repair what they broke
aaronlippold Aug 12, 2026
83f0ea5
fix(docs): document CYPRESS_TESTING and UV_THREADPOOL_SIZE
aaronlippold Aug 12, 2026
564374a
feat(docs): write the getting-started section
aaronlippold Aug 13, 2026
81982a8
ci: report lint without blocking until the backlog is cleared
aaronlippold Aug 13, 2026
3affb93
chore(lint): apply the full rule triage — fix the config, not the count
aaronlippold Aug 13, 2026
47777a9
chore(lint): remove stale disable directives
aaronlippold Aug 13, 2026
c7b1c75
style: apply layout-type autofixes across the monorepo
aaronlippold Aug 13, 2026
aa99a3e
chore(lint): never lint standards files; drop the link-breaking fixer
aaronlippold Aug 13, 2026
84f6123
style: use dot notation for literal string property access
aaronlippold Aug 13, 2026
6bcdb4c
style: use bracket array syntax consistently
aaronlippold Aug 13, 2026
d0d1e5d
style: remove type assertions the compiler proves redundant
aaronlippold Aug 13, 2026
238b861
style: use Record for index signatures
aaronlippold Aug 13, 2026
1ea920e
style: put constructor generics on the constructor
aaronlippold Aug 13, 2026
de3cbbc
style: drop zero fractions from number literals
aaronlippold Aug 13, 2026
bbe0b2d
style: name every catch binding `error`
aaronlippold Aug 13, 2026
f7a5ada
style: make length checks explicit comparisons
aaronlippold Aug 13, 2026
7420f12
style: use replaceAll for global string replacement
aaronlippold Aug 13, 2026
f98fb84
style: group digits with numeric separators
aaronlippold Aug 13, 2026
2f92686
style: pass a limit to split when only a prefix is used
aaronlippold Aug 13, 2026
2bcc665
style: use includes for membership tests
aaronlippold Aug 13, 2026
b5d6d2b
style: use new when constructing builtins
aaronlippold Aug 13, 2026
7c1b6e5
style: use at(-1) for last-element access
aaronlippold Aug 13, 2026
ce6b381
style: drop redundant explicit undefined
aaronlippold Aug 13, 2026
4b1b85c
style: use non-null assertions where only nullability is asserted
aaronlippold Aug 13, 2026
2c4e6d7
fix(security): eliminate computed-key access at the logging trust bou…
aaronlippold Aug 13, 2026
ae19329
feat(docs): WIP — serve the built documentation in-app at /docs
aaronlippold Aug 13, 2026
b864d89
fix(security): Map-backed lookups and caches for scan-file-derived keys
aaronlippold Aug 13, 2026
56860f7
fix(security): remove computed-key access from grouping and descripti…
aaronlippold Aug 13, 2026
d0c0ba3
fix(security): Map-backed resource accumulation in the AWS Config mapper
aaronlippold Aug 13, 2026
a5b1a43
fix(security): finish computed-key elimination across hdf-converters …
aaronlippold Aug 13, 2026
ac03440
chore(lint): object-injection cannot apply to spec fixtures
aaronlippold Aug 13, 2026
bf6948c
fix(security): eliminate computed-key access across the frontend
aaronlippold Aug 13, 2026
cc6383f
fix(security): close the object-injection stream in inspecjs
aaronlippold Aug 13, 2026
406c5bf
fix(backend): three floating promises, two of them live bugs
aaronlippold Aug 13, 2026
14c13a0
fix(frontend): stop losing async flow in stores and routing
aaronlippold Aug 13, 2026
462daf7
fix(frontend): restore the concrete theme shape in gen_visibilities
aaronlippold Aug 13, 2026
0574168
fix(frontend): stop losing async flow in Vue components
aaronlippold Aug 13, 2026
535fdba
refactor(frontend): convert promise chains to async/await in stores a…
aaronlippold Aug 13, 2026
91905e4
refactor(frontend): convert the evaluations store to async/await
aaronlippold Aug 13, 2026
d7f4cfe
refactor(frontend): finish the mechanical promise-chain conversions
aaronlippold Aug 13, 2026
7460763
refactor(frontend): give each vuex action construct its honest form
aaronlippold Aug 13, 2026
7b394c1
refactor(frontend): replace tenable_util's hand-rolled timeout races …
aaronlippold Aug 13, 2026
e2689db
fix(frontend): stop stranding the registration button spinner
aaronlippold Aug 13, 2026
2ebb6ea
fix(hdf-converters): make every template interpolation string-typed
aaronlippold Aug 13, 2026
f8a7d41
fix(lint): string-type the winston printf and snackbar interpolations
aaronlippold Aug 13, 2026
7084de9
style: use utf8 for every text encoding identifier
aaronlippold Aug 13, 2026
b889d52
style: split type-only imports with import type
aaronlippold Aug 13, 2026
c3368ac
chore(lint): execute the Phase D triage decisions
aaronlippold Aug 13, 2026
2b7ae49
refactor: rename code files to their measured case conventions
aaronlippold Aug 13, 2026
30fed7b
fix(lint): clear no-unused-vars with the underscore convention honored
aaronlippold Aug 13, 2026
2689e48
fix(lint): honest test assertions and audited TLS material reads
aaronlippold Aug 13, 2026
1866e5f
fix(security): eliminate dynamic regex construction where a literal o…
aaronlippold Aug 13, 2026
b99728e
fix(lint): chain caught errors as cause and use Object.hasOwn
aaronlippold Aug 13, 2026
cf443bc
fix(lint): declare the checklist fallthrough and drop dead initializers
aaronlippold Aug 13, 2026
001d8de
fix(lint): compare status enums by member, not raw literal
aaronlippold Aug 13, 2026
a324ca7
fix(lint): wrap method references in arrows to pin their receiver
aaronlippold Aug 13, 2026
fb35422
fix(lint): import CJS module members as named imports instead of defa…
aaronlippold Aug 13, 2026
9c513cd
fix(auth): return the validated user from LDAP validate instead of ca…
aaronlippold Aug 13, 2026
30e4535
fix(splunk): make trackJob actually await search job completion
aaronlippold Aug 13, 2026
61c6724
fix(lint): give async-less functions their honest synchronous or prom…
aaronlippold Aug 13, 2026
43ccf3e
fix(lint): unwrap single-element Promise.all in migration transactions
aaronlippold Aug 13, 2026
0da5686
fix(lint): replace then/catch chaining with await where a caller alre…
aaronlippold Aug 13, 2026
a182243
fix(lint): name awaited values instead of member access on await expr…
aaronlippold Aug 13, 2026
6036e67
fix(lint): clear the promise/vitest false-positive tail on Cypress an…
aaronlippold Aug 13, 2026
9287886
fix(lint): hoist function-local regexes to module scope as named cons…
aaronlippold Aug 13, 2026
110da1d
fix(lint): conform type declarations to each package's measured majority
aaronlippold Aug 13, 2026
4ba4b29
fix(lint): use spread over concat, Array.from and slice for array bui…
aaronlippold Aug 13, 2026
05cfd03
fix(lint): drop template-literal wraps that add nothing to their expr…
aaronlippold Aug 13, 2026
b15c1d4
fix(lint): state conditions positively instead of branching on negations
aaronlippold Aug 13, 2026
d368edb
fix(lint): merge consecutive push calls into single multi-argument calls
aaronlippold Aug 13, 2026
d23d5b0
fix(lint): resolve require() usage by module-system contract
aaronlippold Aug 13, 2026
8d0c40b
fix(lint): disambiguate break and continue inside nested loops
aaronlippold Aug 13, 2026
e143437
fix(lint): drop regex flags the patterns cannot use
aaronlippold Aug 13, 2026
ac493d4
fix(lint): conform regex literals to strict-mode escaping
aaronlippold Aug 13, 2026
5ed3557
docs(lint): clear the markdown family across prose, templates, and ma…
aaronlippold Aug 13, 2026
9742c10
fix(lint): call exec on the regex instead of match on the string
aaronlippold Aug 13, 2026
a1eacff
fix(lint): initialize collections with their contents instead of muta…
aaronlippold Aug 13, 2026
edbc79a
fix(lint): stop leaning on push's return value
aaronlippold Aug 13, 2026
6c66f89
fix(lint): use slice for string extraction, preserving each site's ed…
aaronlippold Aug 13, 2026
bed3ec3
fix(lint): pass Boolean directly where a callback only restates it
aaronlippold Aug 13, 2026
e92de94
fix(lint): stop mutating module-scope state from inside functions
aaronlippold Aug 14, 2026
751df51
fix(frontend): type tenable executions as the ScanResults they hold
aaronlippold Aug 14, 2026
0494e50
fix(lint): name non-function values without function-style verbs
aaronlippold Aug 14, 2026
3b235d5
style: order class members canonically (statics, fields, constructor,…
aaronlippold Aug 14, 2026
edf0466
style: use at(-1) for last-element access via slice and length arithm…
aaronlippold Aug 14, 2026
248162f
style: name regex capture groups for what they capture
aaronlippold Aug 14, 2026
9e434f0
style: use Set membership and structuredClone for lookups and deep co…
aaronlippold Aug 14, 2026
de11287
fix(lint): pass replacements as functions and collapse same-operand t…
aaronlippold Aug 14, 2026
3532197
style: replace reduce with the shape each site was building
aaronlippold Aug 14, 2026
bdb2d89
style: pass plain strings to replaceAll where the pattern is one literal
aaronlippold Aug 14, 2026
2104fa3
fix(lint): sort with toSorted instead of mutating in place
aaronlippold Aug 14, 2026
3c6351b
fix(lint): declare the dependencies each package actually imports
aaronlippold Aug 14, 2026
57ded5f
style: drop type annotations that restate literal initializers
aaronlippold Aug 14, 2026
53f7e6b
test: give duplicated suite titles the names of what they actually test
aaronlippold Aug 14, 2026
53e96d0
style: guard and return early instead of wrapping whole bodies in if
aaronlippold Aug 14, 2026
ba8c0a2
style: reference browser globals bare instead of through window
aaronlippold Aug 14, 2026
ee3e8d0
fix(lint): scope n/no-missing-import off the published libs' TS sources
aaronlippold Aug 14, 2026
f15a990
style: coerce with Number and continue early in loops
aaronlippold Aug 14, 2026
fb512ab
style: chain optional accesses instead of guarding each step
aaronlippold Aug 14, 2026
f5d0e9f
style: call array callbacks through explicit arrows
aaronlippold Aug 14, 2026
09d9a2b
style: name intermediates instead of nesting calls four deep
aaronlippold Aug 14, 2026
0d14b7f
style: bound quantifiers explicitly and declare after early exits
aaronlippold Aug 14, 2026
b9bb5c3
style: replace the removed ban-types rule's leftovers
aaronlippold Aug 14, 2026
9222b12
style: flatten with flatMap and compare against undefined directly
aaronlippold Aug 14, 2026
fac57c9
style: export types as types and return booleans directly
aaronlippold Aug 14, 2026
fc032e2
chore(lint): scope four rules to the trees their model actually descr…
aaronlippold Aug 14, 2026
3be0c67
style: hoist shared branch tails and drop redundant coercions
aaronlippold Aug 14, 2026
6bcecdd
fix(frontend): stop valueToSeverity accepting any string as a severity
aaronlippold Aug 14, 2026
94c6a72
style: hoist closures that capture nothing and drop dead spec exports
aaronlippold Aug 14, 2026
16466e8
chore(lint): let Vue install its plugins and fixtures keep their URLs
aaronlippold Aug 14, 2026
bb6d7ad
fix(tests): run the store-sharing specs sequentially and await their …
aaronlippold Aug 14, 2026
1c113e4
fix: render structured values instead of [object Object]
aaronlippold Aug 14, 2026
545680a
chore(lint): let chai state assertions as properties in the e2e tree
aaronlippold Aug 14, 2026
92a6a6f
style: make the flattening worklist explicit and re-export namespaces…
aaronlippold Aug 14, 2026
ab232e3
chore(lint): keep Vue 2's reactive writes and the password rules as t…
aaronlippold Aug 14, 2026
e5bafbd
fix(hdf): stop reversing the source controls in place and throw a rea…
aaronlippold Aug 14, 2026
1b6541e
style: read files through Blob#text and use the modern DOM insertion API
aaronlippold Aug 14, 2026
b10cc42
style: test membership with includes and name what was implicit
aaronlippold Aug 14, 2026
b3caed1
style: prefer the direct array and regex forms across the converters
aaronlippold Aug 14, 2026
0cbf555
fix(auth): restore the disabled-callback fallback and stop leaking a …
aaronlippold Aug 14, 2026
3987161
chore(lint): treat the OIDC mock server as the CJS entry shell it is
aaronlippold Aug 14, 2026
cf217e7
fix(hdf): match a literal decimal point in the attestation frequency
aaronlippold Aug 14, 2026
5b26fab
chore(lint): defer regex safety to the analyzer that models backtracking
aaronlippold Aug 14, 2026
24a7833
test: fail loudly instead of asserting inside a narrowing check
aaronlippold Aug 14, 2026
3cd35e9
fix(evaluations): await the group attachment instead of dropping its …
aaronlippold Aug 14, 2026
1e57fee
ci: make lint blocking now that the repo is clean
aaronlippold Aug 14, 2026
8694cd7
test: pin the two behavior fixes that shipped without coverage
aaronlippold Aug 14, 2026
197e3dc
test: pin the remaining disclosed behavior changes
aaronlippold Aug 14, 2026
ed92b1f
docs(lint): rewrite the ESLint decisions record against the current c…
aaronlippold Aug 14, 2026
ea56457
docs(adr-005): mark the closed phases and record the reformat dependency
aaronlippold Aug 14, 2026
edc89ae
docs(adr-006): describe the crypto module as built
aaronlippold Aug 14, 2026
42b8049
docs(plan): record the PR charter, execution order and effort
aaronlippold Aug 14, 2026
46cb0fd
docs(plan): record where the Playwright migration already lives
aaronlippold Aug 14, 2026
977025c
fix(groups): restore /groups/my ahead of /:id — GUI login was broken
aaronlippold Aug 15, 2026
40e29b5
test(lint-sweep): pin three behavior changes the sweep shipped untested
aaronlippold Aug 15, 2026
3090a5f
docs: regenerate LICENSE.md from the SAF template (disa, ai_assisted)
aaronlippold Aug 15, 2026
d52f618
docs(adr): accept ADR-008 — un-block login at the choke point (path A)
aaronlippold Aug 15, 2026
80d0180
fix(frontend): stop login blocking on application data
aaronlippold Aug 15, 2026
3a09a58
feat(backend): seed stable dev/test users behind a production guard
aaronlippold Aug 15, 2026
c7532b7
feat(backend): seed a demo group with owner and member
aaronlippold Aug 15, 2026
b01a7b6
fix(backend): require an authenticated session for the Tenable proxy
aaronlippold Aug 15, 2026
3bcb788
fix(tenable): reject hosts absent from the configured allowlist
aaronlippold Aug 15, 2026
e2964ec
fix(tenable): stop following redirects on outbound requests
aaronlippold Aug 15, 2026
2a4ea0a
docs: record the backend security workstream as in-scope for review
aaronlippold Aug 15, 2026
55285eb
fix(tenable): filter outbound connections at connect time
aaronlippold Aug 15, 2026
b96cc25
docs: document the Tenable allowlist and address settings
aaronlippold Aug 15, 2026
6c69c3c
docs(authn): cite the tracking card for the LDAP prefer-at disable
aaronlippold Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ apps/frontend/tests
apps/backend/test
test
**/node_modules

# VitePress documentation site (ADR-005 §2.1) — the app image builds from
# explicit COPY paths, so docs/ never entered it implicitly; this makes the
# exclusion explicit. NOTE: shipping the BUILT docs inside the app image for
# offline/airgapped use (Aaron, 2026-08-11) is a separate packaging change and
# will need this entry narrowed (source + node_modules out, built output in).
docs
13 changes: 13 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Commits that changed formatting only, and should be skipped by `git blame`.
#
# Enable locally (once per clone):
# git config blame.ignoreRevsFile .git-blame-ignore-revs
#
# GitHub honours this file automatically in its blame view.
#
# Add the full 40-character SHA of a pure-formatting commit below, one per line,
# with a comment naming it. Only add commits that changed NOTHING but formatting
# — if a commit mixes formatting with behavior, blame must not skip it.

# (none yet — the initial `yarn format` adoption commit belongs here once the
# repo-wide Prettier reformat lands)
212 changes: 212 additions & 0 deletions .github/workflows/build-rpm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
name: Build RPM

# One workflow for both purposes, following redis/memtier_benchmark:
# every PR and master push proves the RPM still builds and installs, and a
# published release additionally uploads the artifacts. Publishing steps are
# gated on the event rather than split into a second workflow, so the thing
# that ships is the thing CI exercised.

on:
pull_request:
paths:
- 'packaging/**'
- 'VERSION'
- '.github/workflows/build-rpm.yml'
push:
branches: [master]
paths:
- 'packaging/**'
- 'VERSION'
- '.github/workflows/build-rpm.yml'
release:
types: [published]
workflow_dispatch:
inputs:
heimdall_cli_ref:
description: 'heimdall-cli ref to build against (tag, branch, or SHA)'
required: false
default: 'main'

env:
# Release builds must pin a tag. Everything else tracks main.
# This value is what the RPM records as the CLI it shipped.
HEIMDALL_CLI_REF: ${{ inputs.heimdall_cli_ref || 'main' }}

jobs:
build:
name: ${{ matrix.distro }} / ${{ matrix.arch }}
runs-on: ${{ matrix.runner }}
container: ${{ matrix.image }}
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- distro: el8
image: rockylinux:8
arch: x86_64
runner: ubuntu-latest
- distro: el9
image: rockylinux:9
arch: x86_64
runner: ubuntu-latest
# Native ARM runners — free for public repositories, and roughly
# 5-10x faster than QEMU emulation for a Node + Go build. The Go CLI
# is compiled natively here rather than cross-compiled.
- distro: el8
image: rockylinux:8
arch: aarch64
runner: ubuntu-24.04-arm
- distro: el9
image: rockylinux:9
arch: aarch64
runner: ubuntu-24.04-arm

steps:
# A bare Rocky container has neither git nor make. actions/checkout needs
# git, and every subsequent step goes through the Makefile — including
# `make deps`, which is what installs the real build dependencies. Both
# have to be bootstrapped here or `make deps` cannot run itself.
- name: Bootstrap git and make
run: |
dnf install -y git make
git --version
make --version | head -1

- uses: actions/checkout@v6
with:
# Full history and tags: `make sources` archives the tag matching the
# VERSION file. A shallow clone has no tags and the build would fail.
fetch-depth: 0
fetch-tags: true

- name: Mark workspace safe
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Install build dependencies
working-directory: packaging/rpm
run: make deps

- name: Install Go (for the heimdall-cli build)
run: dnf install -y golang

- name: Verify spec and repository versions agree
working-directory: packaging/rpm
run: make check-version

# Releases build from the tag matching VERSION. CI builds from HEAD,
# because on a feature branch the tag for an in-progress version does not
# exist yet. DEV=1 makes that explicit rather than silently producing an
# RPM that claims to be a release.
- name: Build RPM
working-directory: packaging/rpm
env:
HEIMDALL_CLI_REF: ${{ env.HEIMDALL_CLI_REF }}
run: |
if [ "${GITHUB_EVENT_NAME}" = "release" ]; then
make rpm
else
make rpm DEV=1
fi

- name: Lint the built packages (advisory)
working-directory: packaging/rpm
continue-on-error: true
run: make lint-rpm

- name: Record what was built
working-directory: packaging/rpm
run: |
find rpmbuild/RPMS rpmbuild/SRPMS -name '*.rpm' -printf '%f\n' | sort
echo "heimdall-cli ref: ${HEIMDALL_CLI_REF}"

- uses: actions/upload-artifact@v7
with:
name: rpm-${{ matrix.distro }}-${{ matrix.arch }}
path: |
packaging/rpm/rpmbuild/RPMS/**/*.rpm
packaging/rpm/rpmbuild/SRPMS/*.rpm
retention-days: 7
if-no-files-found: error

# The highest-value check: install into a clean container with NO build
# dependencies pre-installed, so a missing Requires: fails here rather than on
# a customer's host. Verifies %files claims via rpm -ql.
smoke-test:
name: install ${{ matrix.distro }} / ${{ matrix.arch }}
needs: build
runs-on: ${{ matrix.runner }}
container: ${{ matrix.image }}
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- {distro: el8, image: rockylinux:8, arch: x86_64, runner: ubuntu-latest}
- {distro: el9, image: rockylinux:9, arch: x86_64, runner: ubuntu-latest}
- {distro: el8, image: rockylinux:8, arch: aarch64, runner: ubuntu-24.04-arm}
- {distro: el9, image: rockylinux:9, arch: aarch64, runner: ubuntu-24.04-arm}

steps:
- uses: actions/download-artifact@v8
with:
name: rpm-${{ matrix.distro }}-${{ matrix.arch }}
path: rpms

- name: Install the package and its dependencies
run: |
dnf install -y epel-release || true
rpm_file=$(find rpms -name "heimdall-server-*.${{ matrix.arch }}.rpm" | head -1)
test -n "$rpm_file" || { echo "::error::no binary RPM found"; exit 1; }
echo "Installing $rpm_file"
dnf install -y "$rpm_file"

- name: Verify the package contents match its manifest
run: |
rpm -q heimdall-server
rpm -V heimdall-server || true # config file changes are expected
echo "--- files ---"
rpm -ql heimdall-server | head -40
echo "--- heimdall-cli is present and reports provenance ---"
test -x /usr/bin/heimdall-cli
/usr/bin/heimdall-cli --version

- name: Verify the unit file is valid
run: |
dnf install -y systemd
systemd-analyze verify /usr/lib/systemd/system/heimdall-server.service || true

publish:
name: Attach RPMs to the release
needs: [build, smoke-test]
if: github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: write # upload release assets
id-token: write # build provenance attestation
attestations: write
steps:
- uses: actions/download-artifact@v8
with:
pattern: rpm-*
path: rpms
merge-multiple: true

- name: List artifacts
run: find rpms -name '*.rpm' -printf '%f\n' | sort

# The modern equivalent of GPG-signing in CI: a signed, verifiable
# statement of what built these artifacts and from where. Same
# supply-chain story as npm provenance, without a release key in secrets.
- uses: actions/attest-build-provenance@v4
with:
subject-path: 'rpms/**/*.rpm'

# Pinned to a commit SHA: this is a third-party action holding
# contents: write, and a mutable tag can be repointed at any time.
- uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
files: rpms/**/*.rpm
fail_on_unmatched_files: true
5 changes: 5 additions & 0 deletions .github/workflows/hdfconverter-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ jobs:
- name: Start Mock Sonarqube Server
run: yarn run cypress-test mock-json &

- name: Validate there are no changes between the Tailwind source and the generated assets
run: |
yarn hdf-converters prebuild
yarn hdf-converters validate-generated

- name: Run unit tests
run: yarn hdf-converters test:ci
env:
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/push-to-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ jobs:
- name: Pack all items that are published as packages
run: yarn pack:all

# The published packages rewrite "main" from src/index.ts to lib/index.js
# in prepack and restore it in postpack. Yarn 1 has no try/finally around
# those lifecycle scripts, so a failed pack skips the restore and leaves a
# mutated manifest behind. Running --parallel across three packages means
# one failure can strand another package's manifest. Fail loudly here
# rather than publish a tarball built from a corrupted tree.
- name: Verify manifests were restored after pack
run: |
if ! git diff --exit-code -- '*package.json'; then
echo "::error::package.json was left modified after pack:all — a prepack rewrite was not restored by postpack. Do not publish from this tree."
exit 1
fi
if git ls-files --others --exclude-standard | grep -q 'package.json.orig'; then
echo "::error::A stray package.json.orig remains after pack:all — postpack did not run."
exit 1
fi

- name: Publish Heimdall Lite to NPM
if: always()
run: npx -y npm@latest publish --access public apps/frontend/mitre-heimdall-lite*.tgz
Expand Down
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,25 @@ certs/*.pem

# Database Content
data/*

# prepack/postpack manifest backup.
# The published packages rewrite "main" from src/index.ts to lib/index.js at
# pack time (npm has never supported publishConfig manifest overrides, and
# npm 13 will hard-error on them, so the rewrite is the only option).
# Yarn 1's pack has no try/finally around the lifecycle scripts, so a failed
# pack skips postpack and strands this file next to a mutated package.json.
package.json.orig

# VitePress documentation site (ADR-005). docs/ is deliberately OUTSIDE the yarn
# workspaces globs ("apps/*", "libs/*", "test"), so it has its own package.json
# and yarn.lock and root `yarn install` never sees it. Bare `node_modules` above
# already covers docs/node_modules; VitePress's cache and build output do not.
docs/node_modules
docs/.vitepress/cache
docs/.vitepress/dist

# Playwright MCP writes console logs and page snapshots into the repository as
# it drives the browser — one directory per session, created unconditionally
# and never cleaned up. Live-test evidence belongs in card notes, not in the
# tree, so this is ignored rather than committed.
.playwright-mcp/
33 changes: 33 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Prettier owns formatting for SOURCE. Everything below is either build output,
# third-party/generated content, or fixture data that is compared byte-for-byte
# by tests — reformatting any of it changes meaning, not just appearance.

# Build output and dependencies
**/dist
**/lib
**/node_modules
yarn.lock
package-lock.json

# Test fixture corpora. 365 MB across 249 files; the mapper specs read these
# with readFileSync/JSON.parse and compare results against them, so reformatting
# would both take enormous time and risk changing what the tests assert.
libs/hdf-converters/sample_jsons/

# Generated assets guarded by the `validate-generated` script, which fails the
# build if their committed bytes change (tailwind style.css + the embedded
# strings derived from it).
libs/hdf-converters/data/

# Generated sources — same set the ESLint config ignores, kept in sync.
libs/inspecjs/src/generated_parsers/
libs/hdf-converters/src/ckl-mapper/jsonixMapping.ts

# Static data tables, not code: giant literal maps with no logic. Formatting
# them produces enormous diffs and zero benefit.
**/*MappingData.ts
apps/frontend/src/utilities/cci_util.ts

# The documentation site is an isolated project (ADR-005 §2.1) with its own
# package.json and toolchain; it is not formatted by the application's tooling.
docs/
4 changes: 4 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"singleQuote": true
}
Loading
Loading