feat(vehicles): day log, timeline clamp, overlay chrome #80
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Security | |
| on: | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - 'go.mod' | |
| - 'go.sum' | |
| - 'package.json' | |
| - 'package-lock.json' | |
| - 'web/package.json' | |
| - 'web/package-lock.json' | |
| - 'Dockerfile*' | |
| - 'helm/**' | |
| - 'internal/**' | |
| - 'web/**' | |
| - '.gitleaks.toml' | |
| - 'renovate.json' | |
| - 'scripts/check-security-workflow-pins.go' | |
| - 'scripts/check-security-workflow-pins_test.go' | |
| - '.github/workflows/security.yml' | |
| schedule: | |
| - cron: "0 4 * * 1" | |
| workflow_dispatch: | |
| inputs: | |
| runner: | |
| description: 'Runner to use (manual runs only)' | |
| type: choice | |
| options: | |
| - arc-runner | |
| - ubuntu-latest | |
| default: arc-runner | |
| permissions: | |
| contents: read | |
| security-events: write | |
| env: | |
| # renovate: datasource=docker depName=aquasec/trivy | |
| TRIVY_IMAGE: aquasec/trivy@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969 # 0.74.0 | |
| # renovate: datasource=docker depName=zricethezav/gitleaks | |
| GITLEAKS_IMAGE: zricethezav/gitleaks@sha256:ebfeb6fd4f2c37fa371d3731ebfa662fdf80f93cd37d3b4771bb82263edff8d0 # v8.27.2 | |
| jobs: | |
| security: | |
| name: Security Scan | |
| runs-on: ${{ inputs.runner || 'arc-runner' }} | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 | |
| with: | |
| go-version: "1.25" | |
| - uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 | |
| with: | |
| version: v3.16.0 | |
| - name: Verify workflow supply-chain pins | |
| run: | | |
| go run ./scripts/check-security-workflow-pins.go | |
| go test ./scripts -run TestWorkflowPinChecker | |
| - name: Verify rendered ingress security behavior | |
| shell: bash | |
| run: | | |
| TLS_RENDERED="$(helm template security helm/teslasync \ | |
| --set ingress.enabled=true \ | |
| --set ingress.tls[0].secretName=teslasync-tls \ | |
| --set ingress.tls[0].hosts[0]=teslasync.local)" | |
| grep -Fq 'nginx.ingress.kubernetes.io/force-ssl-redirect: "true"' <<<"$TLS_RENDERED" | |
| grep -Fq 'nginx.ingress.kubernetes.io/ssl-redirect: "true"' <<<"$TLS_RENDERED" | |
| grep -Fq 'CORS_ORIGINS: "https://teslasync.local"' <<<"$TLS_RENDERED" | |
| grep -Fq 'https://fonts.googleapis.com' <<<"$TLS_RENDERED" | |
| grep -Fq "media-src 'self' blob:" <<<"$TLS_RENDERED" | |
| HTTP_RENDERED="$(helm template security helm/teslasync --set ingress.enabled=true)" | |
| if grep -q 'force-ssl-redirect\|ssl-redirect' <<<"$HTTP_RENDERED"; then | |
| echo "plain-HTTP ingress must not force a TLS redirect" >&2 | |
| exit 1 | |
| fi | |
| if helm template security helm/teslasync \ | |
| --set ingressRoute.enabled=true \ | |
| --set ingressRoute.tls.enabled=true > /dev/null 2>&1; then | |
| echo "Traefik TLS must reject an unspecified public CSRF origin" >&2 | |
| exit 1 | |
| fi | |
| TRAEFIK_RENDERED="$(helm template security helm/teslasync \ | |
| --set ingressRoute.enabled=true \ | |
| --set ingressRoute.tls.enabled=true \ | |
| --set config.webEndpoint=https://teslasync.example.com)" | |
| grep -Fq 'stsSeconds: 63072000' <<<"$TRAEFIK_RENDERED" | |
| grep -Fq 'https://fonts.googleapis.com' <<<"$TRAEFIK_RENDERED" | |
| grep -Fq "media-src 'self' blob:" <<<"$TRAEFIK_RENDERED" | |
| - name: Run govulncheck | |
| run: | | |
| go install golang.org/x/vuln/cmd/govulncheck@v1.7.0 | |
| govulncheck ./... | |
| - name: Scan dependencies and filesystem secrets | |
| run: | | |
| docker run --rm -v "$(pwd):/src" -w /src "${TRIVY_IMAGE}" fs \ | |
| --timeout 30m \ | |
| --scanners vuln,secret \ | |
| --skip-dirs .git \ | |
| --skip-dirs node_modules \ | |
| --skip-dirs web/node_modules \ | |
| --skip-dirs .cache \ | |
| --skip-dirs web/.cache \ | |
| --skip-dirs web/test-results \ | |
| --skip-dirs web/playwright-report \ | |
| --skip-dirs coverage \ | |
| --skip-dirs web/coverage \ | |
| --skip-dirs dist \ | |
| --skip-dirs web/dist \ | |
| --skip-files .gitleaks.toml \ | |
| --severity CRITICAL,HIGH \ | |
| --exit-code 1 \ | |
| --format table . | |
| - name: Scan Helm IaC configuration | |
| run: | | |
| docker run --rm -v "$(pwd):/src" -w /src "${TRIVY_IMAGE}" config \ | |
| --severity CRITICAL,HIGH \ | |
| --exit-code 1 \ | |
| --format table helm/teslasync | |
| - name: Scan checkout for exposed secrets | |
| run: | | |
| docker run --rm -v "$(pwd):/repo:ro" "${GITLEAKS_IMAGE}" \ | |
| detect --source=/repo --config=/repo/.gitleaks.toml --no-git --redact --no-banner | |
| - name: Verify Gitleaks policy catches secrets | |
| shell: bash | |
| run: | | |
| # Keep fixtures under the workspace so Docker bind-mounts work on | |
| # self-hosted runners where host /tmp is not visible inside Docker. | |
| fixture="$(pwd)/.gitleaks-policy-fixture" | |
| rm -rf "$fixture" | |
| mkdir -p "$fixture" | |
| trap 'rm -rf "$fixture"' EXIT | |
| write_private_key() { | |
| printf '%s %s\n%s\n%s %s\n' \ | |
| '-----BEGIN' 'PRIVATE KEY-----' \ | |
| 'MIIEpgIBAAKCAQEA7Q0qj5WmCqvTNSiP1w3M9yKf9c2V8zR4' \ | |
| '-----END' 'PRIVATE KEY-----' > "$1" | |
| } | |
| run_detect() { | |
| local source_dir="$1" | |
| docker run --rm \ | |
| -v "$(pwd)/.gitleaks.toml:/config.toml:ro" \ | |
| -v "$fixture:/fixture:ro" \ | |
| "${GITLEAKS_IMAGE}" \ | |
| detect --source="/fixture/${source_dir}" --config=/config.toml --no-git --redact --no-banner | |
| } | |
| n=0 | |
| for fixture_path in production.go internal/negative_test.go web/src/negative.test.ts; do | |
| n=$((n + 1)) | |
| case_dir="pk-${n}" | |
| mkdir -p "$fixture/$case_dir/$(dirname "$fixture_path")" | |
| write_private_key "$fixture/$case_dir/$fixture_path" | |
| if run_detect "$case_dir"; then | |
| echo "Gitleaks failed to detect generated $fixture_path" >&2 | |
| exit 1 | |
| fi | |
| done | |
| write_stopword_fixture() { | |
| printf 'const %s = "%s%s"\n' "$1" "$2" "$3" > "$4" | |
| } | |
| n=0 | |
| for fixture_path in source-stopword.go web/src/stopword.test.ts; do | |
| n=$((n + 1)) | |
| case_dir="stripe-${n}" | |
| mkdir -p "$fixture/$case_dir/$(dirname "$fixture_path")" | |
| write_stopword_fixture token 'sk_live_' 'abcdef1234' "$fixture/$case_dir/$fixture_path" | |
| if run_detect "$case_dir"; then | |
| echo "Gitleaks failed to detect generated Stripe-like $fixture_path" >&2 | |
| exit 1 | |
| fi | |
| done | |
| n=0 | |
| for fixture_path in source-refresh.go web/src/refresh.test.ts; do | |
| n=$((n + 1)) | |
| case_dir="refresh-${n}" | |
| mkdir -p "$fixture/$case_dir/$(dirname "$fixture_path")" | |
| write_stopword_fixture refresh_token 'rt_fake_refresh_token_for_seed_data_only_' 'abc123def456' "$fixture/$case_dir/$fixture_path" | |
| if run_detect "$case_dir"; then | |
| echo "Gitleaks failed to detect generated refresh-token $fixture_path" >&2 | |
| exit 1 | |
| fi | |
| done | |
| mkdir -p "$fixture/allowlist-control/test-results" | |
| write_private_key "$fixture/allowlist-control/test-results/ignored.pem" | |
| docker run --rm \ | |
| -v "$(pwd)/.gitleaks.toml:/config.toml:ro" \ | |
| -v "$fixture:/fixture:ro" \ | |
| "${GITLEAKS_IMAGE}" \ | |
| detect --source=/fixture/allowlist-control --config=/config.toml --no-git --redact --no-banner | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: "20" | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 | |
| with: | |
| languages: go,javascript-typescript | |
| - name: CodeQL autobuild | |
| uses: github/codeql-action/autobuild@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 | |
| - name: CodeQL analysis | |
| uses: github/codeql-action/analyze@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 |