Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI Pipeline

Check warning on line 1 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

excessive-permissions

main.yml:1: overly broad permissions: default permissions used due to no permissions: block

on:
push:
Expand All @@ -12,18 +12,189 @@
GIT_SUBMODULE_STRATEGY: recursive

jobs:
security:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout pull request
uses: actions/checkout@v4

Check failure on line 23 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

unpinned-uses

main.yml:23: unpinned action reference: action is not pinned to a hash (required by blanket policy)
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@v4

Check failure on line 29 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

unpinned-uses

main.yml:29: unpinned action reference: action is not pinned to a hash (required by blanket policy)
with:
node-version: "22"

- name: Set up Python
uses: actions/setup-python@v5

Check failure on line 34 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

unpinned-uses

main.yml:34: unpinned action reference: action is not pinned to a hash (required by blanket policy)
with:
python-version: "3.12"

- name: Initialize CodeQL
uses: github/codeql-action/init@v4

Check failure on line 39 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

unpinned-uses

main.yml:39: unpinned action reference: action is not pinned to a hash (required by blanket policy)
with:
languages: javascript-typescript,python
queries: security-extended

- name: Install security scanners
run: |
python -m pip install --disable-pip-version-check bandit pip-audit semgrep uv

- name: Semgrep
id: semgrep
continue-on-error: true
run: semgrep scan --config p/security-audit --error backend frontend utils

- name: npm audit
id: npm-audit
continue-on-error: true
run: make audit

- name: Gitleaks
id: gitleaks
continue-on-error: true
run: |
docker run --rm -v "$PWD:/repo" ghcr.io/gitleaks/gitleaks:latest \
detect --source=/repo --no-git --redact

- name: ESLint security rules
id: eslint-security
continue-on-error: true
run: |
npm ci --prefix frontend --ignore-scripts
npm ci --prefix backend --ignore-scripts
status=0
for directory in frontend backend; do
(
cd "$directory"
npx eslint "**/*.js" --no-config-lookup --plugin security \
--rule "security/detect-bidi-characters:error" \
--rule "security/detect-buffer-noassert:error" \
--rule "security/detect-child-process:error" \
--rule "security/detect-disable-mustache-escape:error" \
--rule "security/detect-eval-with-expression:error" \
--rule "security/detect-new-buffer:error" \
--rule "security/detect-no-csrf-before-method-override:error" \
--rule "security/detect-non-literal-fs-filename:error" \
--rule "security/detect-non-literal-regexp:error" \
--rule "security/detect-non-literal-require:error" \
--rule "security/detect-object-injection:error" \
--rule "security/detect-possible-timing-attacks:error" \
--rule "security/detect-pseudoRandomBytes:error" \
--rule "security/detect-unsafe-regex:error"
) || status=1
done
exit "$status"

- name: Bandit
id: bandit
continue-on-error: true
run: bandit -r utils/rpcs -ll

- name: pip-audit
id: pip-audit
continue-on-error: true
run: |
status=0
for requirements in utils/rpcs/*/requirements.txt; do
pip-audit --requirement "$requirements" || status=1
done
exit "$status"

- name: Build test image
id: image-build
continue-on-error: true
run: docker build --build-arg ENV=dev --tag care-security-test .

- name: Trivy
id: trivy
if: always() && steps.image-build.outcome == 'success'
continue-on-error: true
run: |
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image --exit-code 1 --severity HIGH,CRITICAL \
care-security-test

- name: Hadolint
id: hadolint
continue-on-error: true
run: |
status=0
for dockerfile in Dockerfile docs/Dockerfile utils/rpcs/*/Dockerfile; do
docker run --rm -i hadolint/hadolint:latest hadolint - < "$dockerfile" || status=1
done
exit "$status"

- name: Zizmor
id: zizmor
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: uvx zizmor --format=github .

# SECURITY-SCANNER-TEST: direct interpolation is intentionally unsafe so
# Zizmor detects template injection on this throwaway branch.
- name: Zizmor test fixture
continue-on-error: true
run: echo "${{ github.event.pull_request.title }}"

Check failure on line 144 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

template-injection

main.yml:144: code injection via template expansion: may expand into attacker-controllable code

- name: Analyze with CodeQL
id: codeql
continue-on-error: true
uses: github/codeql-action/analyze@v4

Check failure on line 149 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

unpinned-uses

main.yml:149: unpinned action reference: action is not pinned to a hash (required by blanket policy)

- name: Fail when any blocking scanner reports findings
if: always()
env:
SEMGREP: ${{ steps.semgrep.outcome }}
NPM_AUDIT: ${{ steps.npm-audit.outcome }}
GITLEAKS: ${{ steps.gitleaks.outcome }}
ESLINT_SECURITY: ${{ steps.eslint-security.outcome }}
BANDIT: ${{ steps.bandit.outcome }}
PIP_AUDIT: ${{ steps.pip-audit.outcome }}
IMAGE_BUILD: ${{ steps.image-build.outcome }}
TRIVY: ${{ steps.trivy.outcome }}
HADOLINT: ${{ steps.hadolint.outcome }}
ZIZMOR: ${{ steps.zizmor.outcome }}
CODEQL: ${{ steps.codeql.outcome }}
run: |
printf '%-18s %s\n' \
Semgrep "$SEMGREP" \
npm-audit "$NPM_AUDIT" \
Gitleaks "$GITLEAKS" \
ESLint-security "$ESLINT_SECURITY" \
Bandit "$BANDIT" \
pip-audit "$PIP_AUDIT" \
image-build "$IMAGE_BUILD" \
Trivy "$TRIVY" \
Hadolint "$HADOLINT" \
Zizmor "$ZIZMOR" \
CodeQL "$CODEQL"
for result in \
"$SEMGREP" "$NPM_AUDIT" "$GITLEAKS" "$ESLINT_SECURITY" \
"$BANDIT" "$PIP_AUDIT" "$IMAGE_BUILD" "$TRIVY" \
"$HADOLINT" "$ZIZMOR" "$CODEQL"
do
[ "$result" = "success" ] || exit 1
done

build:

Check warning on line 186 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

excessive-permissions

main.yml:186: overly broad permissions: default permissions used due to no permissions: block
runs-on: ubuntu-latest
services:
docker:
image: docker:24.0.7-dind
options: --privileged
steps:
- uses: actions/checkout@v4

Check failure on line 193 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

unpinned-uses

main.yml:193: unpinned action reference: action is not pinned to a hash (required by blanket policy)

Check warning on line 193 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

artipacked

main.yml:193: credential persistence through GitHub Actions artifacts: does not set persist-credentials: false
with:
submodules: recursive
- name: Log in to Docker Hub
uses: docker/login-action@v3

Check failure on line 197 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

unpinned-uses

main.yml:197: unpinned action reference: action is not pinned to a hash (required by blanket policy)
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_TOKEN }}
Expand Down Expand Up @@ -58,8 +229,8 @@
run: tar -xzvf docs.tar.gz
- name: Prepare branch docs folder
run: |
mkdir -p publish/${{ github.ref_name }}

Check failure on line 232 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

template-injection

main.yml:232: code injection via template expansion: may expand into attacker-controllable code
cp -r docs/build/html/. publish/${{ github.ref_name }}/

Check failure on line 233 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

template-injection

main.yml:233: code injection via template expansion: may expand into attacker-controllable code
cat > publish/index.html <<'EOF'
<!doctype html>
<html lang="en">
Expand All @@ -84,11 +255,11 @@
publish_dir: ./publish
keep_files: true

audit:

Check warning on line 258 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

excessive-permissions

main.yml:258: overly broad permissions: default permissions used due to no permissions: block
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4

Check warning on line 262 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

artipacked

main.yml:262: credential persistence through GitHub Actions artifacts: does not set persist-credentials: false
with:
submodules: recursive
- uses: actions/setup-node@v4
Expand All @@ -103,11 +274,11 @@
- name: Run npm audit
run: make audit

lint:

Check warning on line 277 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

excessive-permissions

main.yml:277: overly broad permissions: default permissions used due to no permissions: block
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4

Check warning on line 281 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

artipacked

main.yml:281: credential persistence through GitHub Actions artifacts: does not set persist-credentials: false
with:
submodules: recursive
- uses: actions/setup-node@v4
Expand All @@ -118,12 +289,12 @@
- name: Run linter
run: make lint

sync_to_gitlab:

Check warning on line 292 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

excessive-permissions

main.yml:292: overly broad permissions: default permissions used due to no permissions: block
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev'
steps:
- uses: actions/checkout@v4

Check warning on line 297 in .github/workflows/main.yml

View workflow job for this annotation

GitHub Actions / security

artipacked

main.yml:297: credential persistence through GitHub Actions artifacts: does not set persist-credentials: false
with:
fetch-depth: 0

Expand Down
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# syntax=docker/dockerfile:1
FROM node:20.19-alpine
# SECURITY-SCANNER-TEST: old Alpine base should be reported by Trivy.
FROM node:20-alpine3.18
ARG ENV
ENV ENV=$ENV

# Install requirements
RUN npm install --global npm

# Install make
# SECURITY-SCANNER-TEST: missing --no-cache should be reported by Hadolint.
RUN apk add make

# Install msmtp (for sending emails)
Expand Down
Loading
Loading