security: merge the hardening branch into main (2/2 — after insight-front#258) - #2143
Conversation
…#2118) Set readOnlyRootFilesystem and capabilities.drop: ["ALL"] on every container in the analytics, authenticator and identity-resolution charts, with emptyDir volumes on exactly the paths each container writes. Writes were enumerated with `docker diff` on the published images against a local mariadb/clickhouse/redis/fakeidp stack, driven by the chart's own rendered ConfigMap: /app/data server.home_dir -- every container /tmp/<svc>-grpc grpc-hub UDS -- the three long-running servers /tmp pid + *_temp -- the authn-tls nginx sidecar migrate, persons-seed and persons-sync never start grpc-hub, so they mount /app/data only. With /app/data but no /tmp the servers stay Running with both probes green while grpc-hub fails to bind its socket, so that volume is load-bearing rather than defensive. The authn-tls sidecar gets the same two controls and its own /tmp volume, kept separate from the authenticator's: that one carries the grpc-hub socket. It reaches the scan only when tlsDiscovery is enabled, which the umbrella does and the subchart defaults do not. Rendered-chart misconfig scan: 17 HIGH -> 10, clearing all seven KSV-0014 on these charts. helm lint clean; the seed/sync CronJob contract suite passes. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
) airbyte-cdk pins nltk==3.9.1 in every CDK connector, and additionally langchain-core==0.1.42 in the 6.60.x line the nocode test harness runs on. Both pins have a released fix for a CRITICAL (CVE-2025-14009, CVE-2025-68664), and no downstream project can move them by declaring a version floor. Declare uv override-dependencies so a resolved graph lands on the fixed versions. For the connectors this also makes the declared graph agree with the image, which already installs nltk 3.10.0 over the pin with --no-deps. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
A version pushed in the last few days is where a compromised maintainer account surfaces first, and an override that only sets a floor would resolve straight to it. Verified the cooldown does not undo the point of the override: resolution still lands on nltk 3.10.0 and a langchain-core above the fix, with the newest release held back as intended. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
Both Deployments ran with the default context, so a container could escalate privileges and kept the full capability set. Adopt the shape already used by the gateway chart: non-root UID/GID 1000 at pod level, no privilege escalation and all capabilities dropped at container level. fakeidp additionally gets readOnlyRootFilesystem — it never writes to disk. keycloak does not: start-dev re-augments Quarkus into /opt/keycloak/lib/quarkus on every boot, and backing that path with an emptyDir hides the image's quarkus-application.dat. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
seed and toolbox run as Kubernetes Jobs and mount nothing from a host, so a fixed UID is unambiguous there. declarative-connector receives only read-only mounts and writes to stdout. rust-watch keeps its writable paths in named volumes, which Docker seeds from the image including ownership, so /target and the cargo caches are chowned before the volume is created. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
#1340) Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
Decided by QA: the image is not part of the delivered product, so the condition the rule guards against does not arise. Scoped to that one path, with the reasoning in the waiver itself rather than in a separate document that would drift from it. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
The YAML ignore file is the only form that can scope a waiver to a path, and Trivy does not auto-detect it — verified: the waiver is ignored without --ignorefile and applied with it. The file is committed, so the absent-file FATAL cannot trigger. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
They do not exist in rust:1.95-bookworm — /usr/local/cargo holds only bin and env — so chown -R exited non-zero and broke the build. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
Same change as the rest of the workflows, kept apart because this file publishes every image and the umbrella chart: a problem here stops delivery rather than a test, so it needs to be reviewable and revertable on its own. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
The Deployment declared no securityContext, so nginx kept root and the full capability set. Pairs with the unprivileged image in constructorfabric/insight-front: uid 101, port 8080. Only the container port moves. The Service resolves the container by port name and still listens on 80, so the gateway's frontUrl is unchanged. readOnlyRootFilesystem is left off: the entrypoint renders the nginx config from /etc/nginx/templates at start and nginx needs a writable cache directory. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
…akeidp-keycloak fix(helm): declare securityContext for fakeidp and keycloak (#2084)
…nroot fix(images): run the tooling images as a non-root user
…images ci(security): pin third-party actions to digests in build-images.yml
…curitycontext fix(helm): run the frontend as a non-root user on 8080 (#1340)
…2120) airbyte-cdk 6.60.x resolves cryptography 44.0.3, which carries a Bleichenbacher timing oracle in PKCS#1 v1.5 decryption (CVE-2026-26007, fixed in 46.0.5) and GHSA-537c-gmf6-5ccf (fixed in 48.0.1). The override resolves 49.0.0. Regenerating the lock from a clean checkout, as trivy.yml does, and rescanning: both findings clear. Harness suites with the override applied: 42 passed, 1 skipped -- identical to baseline. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
* ci(security): pin third-party actions to digests, add Dependabot A tag is a moving reference: the action's owner can repoint it, and so can whoever takes over that account, after which the repointed code runs on our runners with the job's token. A digest cannot be repointed. Pinning alone would freeze these actions, so Dependabot refreshes them weekly, in two groups — actions and base images — because a base-image bump is a rebuild that can change runtime behaviour and must not block an unrelated action bump. Covers six workflows. build-images.yml is pinned separately: it publishes every image and the umbrella chart, so it is kept reviewable and revertable on its own. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech> * ci(security): add a Dependabot cooldown, route review through CODEOWNERS Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech> * ci(security): let Dependabot refresh the npm tree Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech> * ci(security): drop the npm ecosystem from this repo (no package manifest is tracked) Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech> * ci(security): drop persisted checkout credentials, correct the ADR and SOP actions/checkout leaves the job token in .git/config by default, so any later step — including a third-party action — can read it. None of these workflows write back, so nothing depended on it. Also: an action bump can change behaviour too, the two-per-week figure covers scheduled updates only, and the SOP grep missed any image whose tag is not purely numeric. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech> * chore(ci): drop the ADR and the .NET restore output from this branch The ADR restated a practice the workflows already carry in comments, so it documented convention rather than a decision. Nothing referenced it. The `obj/` files under services/identity are NuGet restore output for a service the tree no longer contains -- a stale working directory swept in by a broad `git add`. They embed machine-local paths and were never meant to be tracked. Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech> --------- Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech> Co-authored-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
…emaining-charts fix(helm): read-only root filesystem for the remaining backend charts (#2118)
…itical-cves fix(ingestion): resolve nltk and langchain-core to fixed versions (#2061)
…rrent (#2120) The scan reports eight highs on deploy/seed for jinja2 2.11.3, werkzeug 2.1.2 and sqlparse 0.4.3 -- a 2022 dependency set nothing installs. uv resolves the base dependencies and the dev extra together, and mypy==2.1.0 needs pathspec>=1.0.0 while dbt-core on the 1.11 line caps pathspec below 0.13. The pin could not move, so dbt-core gave: the resolver walked it back to 1.2.6, before that constraint existed. dbt-core 1.12 raised its own cap to pathspec<1.1 (dbt-labs/dbt-core#12385), so a current mypy resolves against a current dbt-core. The extra now asks for mypy>=2,<3 and the graph comes out at dbt-core 1.12.0, dbt-adapters 1.24.5, pathspec 1.0.4, mypy 2.3.0. dbt-clickhouse settles on 1.9.3 rather than 1.10.1: the 1.10 line caps dbt-adapters below 1.23.0, under dbt-core 1.12.0's 1.24.5 floor, and 1.9.3 carries no adapter bound at all. ruff moves 0.15.16 -> 0.15.21 to match the ruff-pre-commit hook, which was already on v0.15.21. Two different pins meant a local run and the commit hook could reach different verdicts. Locking from clean: dbt-clickhouse 1.9.3, dbt-core 1.12.0, jinja2 3.1.6, sqlparse 0.5.5, no werkzeug -- 0 CRITICAL and 0 HIGH repo-wide. The documented recipe still works end to end: `pip install -e '.[dev]'` then `ruff check .` (All checks passed) and `mypy .` (14 files, no issues). Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
…aining-highs fix(deps): clear the remaining uv.lock highs — cryptography override, seed resolution (#2120)
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughThe PR hardens CI action references, dependency resolution, Docker images, Kubernetes workloads, and Trivy scanning. It adds Dependabot scheduling, scoped scanner waivers, non-root execution, read-only filesystems, dropped capabilities, and writable runtime volumes. ChangesSecurity and dependency hardening
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/build-images.yml:
- Around line 74-75: Update the actions/checkout steps in the build jobs at the
specified unprotected locations to set persist-credentials to false, including
the checkout adjacent to dorny/paths-filter. Leave the checkout steps used for
pushing at the later protected locations unchanged so they retain credential
persistence.
- Around line 996-999: Update both actions/create-github-app-token steps in the
workflow to explicitly request only repository Contents access by adding
permission-contents: write alongside the existing app-id and private-key inputs.
Do not add any other permission-* inputs, preserving the token’s use for
checkout and push.
In @.github/workflows/trivy.yml:
- Line 48: Update the comment adjacent to the Trivy ignore-file configuration to
describe the committed .trivyignore.yaml file and its path-scoped AVD-DS-0002
waiver, removing outdated references to .trivyignore and date-scoped CVE syntax.
- Around line 48-53: Move the --ignorefile argument in each Trivy filesystem
scan command after "$TRIVY_IMAGE" and the fs subcommand, including the scan
blocks near the referenced locations, so Docker receives only its own options
and Trivy receives the ignore-file option.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4a2ba549-4f3d-42be-8d4e-bff8225296e3
📒 Files selected for processing (32)
.github/dependabot.yml.github/workflows/authenticator.yml.github/workflows/build-images.yml.github/workflows/ci.yml.github/workflows/e2e-bronze-to-api.yml.github/workflows/gateway.yml.github/workflows/ghcr-cleanup.yml.github/workflows/openapi-specs.yml.github/workflows/trivy.yml.trivyignore.yamldeploy/compose/rust-watch.Dockerfiledeploy/seed/Dockerfiledeploy/seed/pyproject.tomldocs/components/deployment/specs/sop/scanner-image-refresh.mdsrc/backend/services/analytics/helm/templates/deployment.yamlsrc/backend/services/authenticator/helm/templates/deployment.yamlsrc/backend/services/fakeidp/helm/templates/deployment.yamlsrc/backend/services/identity-resolution/helm/templates/deployment.yamlsrc/backend/services/identity-resolution/helm/templates/seed-cronjob.yamlsrc/backend/services/identity-resolution/helm/templates/sync-cronjob.yamlsrc/backend/services/keycloak/helm/templates/deployment.yamlsrc/frontend/helm/templates/deployment.yamlsrc/ingestion/connectors/ai/github-copilot/pyproject.tomlsrc/ingestion/connectors/crm/hubspot/pyproject.tomlsrc/ingestion/connectors/crm/salesforce/pyproject.tomlsrc/ingestion/connectors/git/bitbucket-cloud/pyproject.tomlsrc/ingestion/connectors/git/github-v2/pyproject.tomlsrc/ingestion/connectors/git/gitlab/pyproject.tomlsrc/ingestion/connectors/hr-directory/active-directory/pyproject.tomlsrc/ingestion/tests/connectors/pyproject.tomlsrc/ingestion/tools/declarative-connector/Dockerfilesrc/ingestion/tools/toolbox/Dockerfile
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | ||
| - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow outline =="
wc -l .github/workflows/build-images.yml
rg -n "uses: actions/checkout|persist-credentials|permissions:|GITHUB_TOKEN|docker build|scripts|paths-filter|push" .github/workflows/build-images.yml
echo
echo "== checkout context snippets =="
python3 - <<'PY'
from pathlib import Path
p = Path(".github/workflows/build-images.yml")
lines = p.read_text().splitlines()
for i,line in enumerate(lines, start=1):
if "actions/checkout" in line:
start=max(1,i-5); end=min(len(lines),i+12)
print(f"\n--- context at line {i} ---")
for j in range(start,end+1):
print(f"{j:5}: {lines[j-1]}")
PYRepository: constructorfabric/insight
Length of output: 22530
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== relevant workflow headers and job names =="
sed -n '1,180p' .github/workflows/build-images.yml | sed -n '1,180p'
echo
sed -n '220,270p' .github/workflows/build-images.yml
echo
sed -n '320,375p' .github/workflows/build-images.yml
echo
sed -n '420,475p' .github/workflows/build-images.yml
echo
sed -n '530,580p' .github/workflows/build-images.yml
echo
sed -n '645,690p' .github/workflows/build-images.yml
echo
sed -n '805,850p' .github/workflows/build-images.yml
echo
echo "== changed scripts/files referenced by workflow =="
sed -n '1,20p' .github/workflows/build-images.yml
fd -a '.github/workflows/scripts' .github/workflows || trueRepository: constructorfabric/insight
Length of output: 23204
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== .github/workflows/scripts contents =="
find .github/workflows/scripts -type f -print | sort | while IFS= read -r f; do
echo "--- $f ---"
wc -l "$f"
sed -n '1,220p' "$f"
done
echo
echo "== read-only YAML/action/config script usage check =="
python3 - <<'PY'
from pathlib import Path
import re
wf = Path(".github/workflows/build-images.yml").read_text(linesep="\n").splitlines()
scripts = {}
for root, _, files in sorted([[*(Path(".github/workflows/scripts").iterdir())]] if Path(".github/workflows/scripts").exists() else []):
pass
# Actually pathlib only dirs
files = sorted(Path(".github/workflows/scripts").glob("*")) if Path(".github/workflows/scripts").exists() else []
for f in files:
if not f.is_file(): continue
scripts[f.name] = f.read_text().splitlines()
for key, name in [
("discover-image-matrix", "python3 .github/workflows/scripts/discover-image-matrix.py"),
("bump-service-appversions", ".github/workflows/scripts/bump-service-appversions.sh"),
("bump-descriptor-version", ".github/workflows/scripts/bump-descriptor-version.sh"),
]:
script = scripts.get(key)
pattern = "(?:python3 |)(\\.github/workflows/scripts/" + re.escape(key) + ".*|.*" + re.escape(key) + ".*|discover-image-matrix|bump-service-appversions|bump-descriptor-version)"
matches = []
for i,line in enumerate(wf,1):
if key in line:
matches.append((i,line[:180]))
print(f"{key}: lines {matches}")
PYRepository: constructorfabric/insight
Length of output: 12938
Disable checkout credential persistence in the build jobs.
actions/checkout writes GITHUB_TOKEN to .git/config by default. These jobs run workflow scripts or Docker build content before any write-only registry login, so non-push steps should not keep the token in Git. Add persist-credentials: false to the unprotected checkouts at lines 74, 180, 268, 369, 469, 680, and 846. Keep the checkout token persistence at lines 1001 and 1184 only because those steps need the remote token for pushing.
🧰 Tools
🪛 zizmor (1.28.0)
[warning] 74-74: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/build-images.yml around lines 74 - 75, Update the
actions/checkout steps in the build jobs at the specified unprotected locations
to set persist-credentials to false, including the checkout adjacent to
dorny/paths-filter. Leave the checkout steps used for pushing at the later
protected locations unchanged so they retain credential persistence.
Source: Linters/SAST tools
| uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2 | ||
| with: | ||
| app-id: ${{ vars.AUTOMATION_APP_ID }} | ||
| private-key: ${{ secrets.AUTOMATION_APP_PRIVATE_KEY }} |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | rg '(\.github/workflows/build-images.yml|package.json|package-lock.json|pnpm-lock.yaml|yarn.lock)$' || true
echo
echo "Workflow relevant lines around create-github-app-token:"
sed -n '970,1010p' .github/workflows/build-images.yml 2>/dev/null || true
echo
sed -n '1160,1195p' .github/workflows/build-images.yml 2>/dev/null || true
echo
echo "Search for permissions usage in workflow:"
rg -n "permissions:|create-github-app-token|permission-|pull_request|push|contents|permissions" .github/workflows/build-images.yml || true
echo
echo "Search for action in repository (maybe vendored):"
rg -n "create-github-app-token|createGithubAppToken|permissions" .github/workflows/build-images.yml .github/actions 2>/dev/null || trueRepository: constructorfabric/insight
Length of output: 14948
🌐 Web query:
actions/create-github-app-token inputs permission default omitted installs create token
💡 Result:
When using the actions/create-github-app-token GitHub Action, if you omit the permission inputs (the optional permission-* parameters), the generated installation access token defaults to inheriting all permissions currently granted to the GitHub App installation [1][2][3]. In this default state, the token receives the full set of permissions defined in the app's installation configuration [4][5]. Because this can grant more access than may be necessary for a specific workflow task, it is considered a best practice to explicitly define only the required permissions using the permission- prefix followed by the specific permission name (e.g., permission-contents: read) [1][5]. Key details regarding this behavior include: - Inheritance: If no permission-* inputs are provided, the action effectively requests a token with the maximum scope available to that installation [4][6]. - Security Recommendation: GitHub and the action maintainers recommend explicitly listing required permissions to follow the principle of least privilege [1][2][5]. - Validation: If you explicitly set a permission that the GitHub App installation does not possess, the API call to generate the token will fail [6][2][3]. - Implementation: Permissions are parsed from environment variables (prefixed with INPUT_PERMISSION-), normalized, and combined into a request object used when interacting with the GitHub API [4][6]. If you encounter issues when using specific permissions, it is often because the requested subset does not cover the requirements of the workflow tasks, whereas omitting them (defaulting to all) allows the action to succeed by providing broader access [7].
Citations:
- 1: https://github.com/actions/create-github-app-token
- 2: https://github.com/marketplace/actions/create-github-app-token
- 3: https://github.com/actions/create-github-app-token/blob/5c1e00d1af39c515564da2ae21cc9dedf0793346/README.md
- 4: https://deepwiki.com/actions/create-github-app-token/4.2-permission-system
- 5: https://deepwiki.com/actions/create-github-app-token/2-getting-started
- 6: https://deepwiki.com/actions/create-github-app-token/4.1-action-inputs
- 7: Changes in permission-* handling since version 2.0.4 actions/create-github-app-token#248
Restrict the GitHub App token permissions.
This workflow does not request permission-* inputs from actions/create-github-app-token, so the generated installation token inherits the App installation’s configured permissions. These jobs need repository Contents access for checkout and push. Set permission-contents: write and omit any extra scopes.
Proposed fix
with:
app-id: ${{ vars.AUTOMATION_APP_ID }}
private-key: ${{ secrets.AUTOMATION_APP_PRIVATE_KEY }}
+ permission-contents: writeAlso applies to: 1179-1182
🧰 Tools
🪛 zizmor (1.28.0)
[error] 996-996: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/build-images.yml around lines 996 - 999, Update both
actions/create-github-app-token steps in the workflow to explicitly request only
repository Contents access by adding permission-contents: write alongside the
existing app-id and private-key inputs. Do not add any other permission-*
inputs, preserving the token’s use for checkout and push.
Source: Linters/SAST tools
| - name: Trivy fs scan — CRITICAL only (report-only) | ||
| # Waivers: `.trivyignore` at the repo root, date-scoped — `CVE-... exp:YYYY-MM-DD # <issue>`. | ||
| # Keep `-w /src`; `--ignorefile` exits FATAL when the file is absent. | ||
| # `.trivyignore.yaml` must be passed explicitly — the YAML form is not auto-detected. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update the adjacent waiver comment.
The preceding comment refers to .trivyignore and date-scoped CVE syntax. This workflow now uses .trivyignore.yaml with a path-scoped AVD-DS-0002 waiver. Keep the comment aligned with the committed file.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/trivy.yml at line 48, Update the comment adjacent to the
Trivy ignore-file configuration to describe the committed .trivyignore.yaml file
and its path-scoped AVD-DS-0002 waiver, removing outdated references to
.trivyignore and date-scoped CVE syntax.
The three scan steps carried a literal backslash-n where a line continuation
belongs, so the command collapsed onto one line and --ignorefile landed among
the `docker run` flags. Docker rejects it:
unknown flag: --ignorefile
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
exit code 125
Both trivy jobs fail that way, which also means no SARIF is uploaded and Code
Scanning stops being refreshed. It went unseen because trivy.yml only runs on
main and on pull requests into it; every branch so far targeted
security-hardening, where the workflow reports `skipping`.
Moving the flag after the image and the `fs` subcommand is the whole fix. Also
the first time the .trivyignore.yaml waiver actually takes effect.
Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
Merges the
security-hardeningbranch intomain. Eight PRs, taken out of the 2026-07-28 releaseand collected here since. Tracked by #2020 and #2079.
nltkandlangchain-coreresolved to fixed versions through[tool.uv] override-dependencieson 8 projects, plus a 7-dayexclude-newercooldownsecurityContextfor the fakeidp and keycloak Deployments--no-install-recommendson the toolbox nodejs install; a path-scoped waiver for the e2e runner in.trivyignore.yamlpersist-credentials: falseon all 19 checkout steps; the scanner-refresh SOPbuild-images.yml, kept separate because it publishes every image and the umbrella chartreadOnlyRootFilesystemandcapabilities.drop: ["ALL"]on every container in the analytics, authenticator and identity-resolution charts, including both CronJobs and theauthn-tlssidecar, withemptyDirvolumes on exactly the paths each container writescryptographyoverride for the connector harness;deploy/seedraised past the mypy/dbt-corepathspecsplit--ignorefilemoved onto thetrivycommand; it sat among thedocker runflags behind a literal `32 files, +461/−132. Merges into
mainwith no conflicts (verified in a scratch worktree offorigin/main).Merge order — one hard constraint
constructorfabric/insight-front'ssecurity-hardeningmust merge first, and this shouldfollow immediately.
The frontend chart lives here; the image it deploys lives there. #2095 sets
containerPort: 8080and
runAsUser: 101; insight-front#252 moves the image to unprivileged nginx on 8080. Until bothare on
mainand one umbrella chart publish has happened after both, the chart and the image namedifferent ports and the frontend pod does not become ready in insight-dev.
This merge touches 17 files under the
build-images.ymlpath filters, so it republishes theumbrella chart on its own. Do not leave a gitops cycle between the two merges. If the window needs
closing by hand, fire
build-images.ymlviaworkflow_dispatchwith the currentfrontend_tagonce both are in.
What this does not close
Three findings stay open deliberately, each recorded with its reasoning:
AVD-KSV-0014on keycloak — accepted risk.start-devre-augments Quarkus into/opt/keycloak/lib/quarkuson every boot; measured, a read-only root throwsReadOnlyFileSystemException, and anemptyDirhides the file the image ships. Not suppressed,so it stays visible in every scan.
AVD-KSV-0014on the frontend chart, same shape, also measured.AVD-DS-0002on the e2e runner image — not applicable, decided by QA; waived path-scoped in.trivyignore.yaml.Separately, roughly 22 HIGH live inside the built
insight-toolboximage (tar,minimatch,kubectl,yqand friends underusr/lib/node_modulesandusr/local/bin). Those come from theimage scan, not from anything in this tree, and no PR here addresses them.
Test plan
security-hardeningmerges intoorigin/mainwith no conflictstrivy fs --scanners vuln --include-dev-depsover all 11 Python projects, locks regeneratedfrom clean exactly as
trivy.ymldoes: 0 CRITICAL, 0 HIGHtrivy fs --scanners misconfigover the rendered charts: 17 HIGH → 10, all sevenKSV-0014on analytics / authenticator / identity-resolution cleared; the remainder iskeycloak and the frontend chart above
helm lintclean on every chart; the identity-resolution CronJob contract suite passes(17 tests)
pytest --suites-only: 42 passed, 1 skipped — the pre-change baselinemainbuild-images.ymlpublishes the umbrella chartsecurityContext— analytics, authenticator, identity-resolution, fakeidp, keycloak,frontend
trivy.ymlrun againstmainreports 0 CRITICAL and roughly 25HIGH, down from 9 and 131
Summary by CodeRabbit
Security
Maintenance
Documentation