svelte-security¶
The web-UI sibling of go-security /
rust-security: one job per scanner, each
opt-out-able, tool images/versions pinned per input. Three layers of
coverage, all free / OSS:
| Layer | Jobs |
|---|---|
| Known vulns | osv-scanner (OSV-DB, incl. the MAL- malicious-packages feed), npm-audit, retire |
| SAST / XSS | semgrep (p/javascript, p/typescript, p/xss, p/secrets) |
| Provenance / integrity | audit-signatures (npm registry signatures), lockfile-lint (every resolved URL is HTTPS + the official registry — a dependency-confusion guard) |
| SBOM | sbom (cyclonedx-npm, informational, non-gating) |
| Secrets | gitleaks (repo-wide, not path-filtered) |
retire scans the built bundle, not node_modules — a raw
node_modules scan flags vulnerable libraries vendored inside dev
tooling (e.g. svelte-check bundling an old lodash) that never reach
users, which would fail essentially every real project. The job builds the
bundle first, then scans output_dir. Declared deps stay covered by
npm-audit + osv-scanner (lockfile-based).
The malicious-package execution vector is neutralised by npm ci
--ignore-scripts in the jobs that install (retire, audit-signatures).
Pair with Renovate minimumReleaseAge in the consumer for the
novel-malicious-release window.
Always-on — unlike the other svelte-* components, this carries no
change-detection changes input; every MR re-checks deps against the
latest advisory DB and re-scans for secrets. See
Explanation: security, always-on.
paths is required (no default).
Jobs¶
| Job | What it runs |
|---|---|
semgrep |
semgrep --error --severity $[[ inputs.semgrep_severity ]] $[[ inputs.semgrep_config ]] $[[ inputs.paths ]] |
osv-scanner |
Per path: /osv-scanner -L "$dir/package-lock.json" |
npm-audit |
Per path: npm audit --audit-level=$[[ inputs.audit_level ]] |
retire |
Per path: npm ci --ignore-scripts && npm run $[[ inputs.build_script ]] && npx retire@$[[ inputs.retire_version ]] --path "$[[ inputs.output_dir ]]" |
audit-signatures |
Per path: npm ci --ignore-scripts && npm audit signatures |
lockfile-lint |
Per path: npx lockfile-lint@$[[ inputs.lockfile_lint_version ]] --path package-lock.json --type npm --validate-https --allowed-hosts $[[ inputs.lockfile_lint_allowed_hosts ]] |
sbom |
Per path: npx @cyclonedx/cyclonedx-npm@$[[ inputs.cyclonedx_version ]] --package-lock-only, artifacts under sbom/ |
gitleaks |
gitleaks detect, scoped to the MR diff base |
Inputs¶
| Input | Type | Default | Description |
|---|---|---|---|
stage |
string | security |
GitLab CI stage. |
if |
string | '$CI_PIPELINE_SOURCE == "merge_request_event"' |
Gating rules:if:. No change-detection — runs on every MR. |
paths |
string | (required) | Space-separated frontend root(s). |
npm_image |
string | dev-tools:v0.1.2 |
Image for the npm-based jobs. |
semgrep_image |
string | "returntocorp/semgrep:1.163.0" |
Semgrep image (shared pin with go-security). |
semgrep_config |
string | "--config p/javascript --config p/typescript --config p/xss --config p/secrets" |
Semgrep ruleset flags. |
semgrep_severity |
string | "ERROR" |
Minimum severity semgrep fails on. |
osv_scanner_image |
string | "ghcr.io/google/osv-scanner:v2.3.8" |
OSV-Scanner image. |
gitleaks_image |
string | "zricethezav/gitleaks:v8.30.1" |
Gitleaks image (shared pin with go-security). |
audit_level |
string | "high" |
npm audit --audit-level= threshold. |
lockfile_lint_allowed_hosts |
string | "npm" |
lockfile-lint --allowed-hosts registry alias. |
build_script |
string | "build" |
npm script producing the shipped bundle, built before retire scans it. |
output_dir |
string | "embed" |
Built-bundle directory retire scans. |
retire_version |
string | "5.4.3" |
retire.js version (Renovate-bumped). |
lockfile_lint_version |
string | "5.0.0" |
lockfile-lint version. |
cyclonedx_version |
string | "5.0.0" |
@cyclonedx/cyclonedx-npm version. |
Usage¶
include:
- component: gitlab.com/phpboyscout/cicd/[email protected]
inputs:
paths: "pkg/studio/web"
See also¶
svelte-build,svelte-lint,svelte-test- Explanation: security, always-on
- Spec:
2026-06-23-svelte-frontend-track