Skip to content

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