Skip to content
Merged
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
19 changes: 13 additions & 6 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,17 @@ Rules that apply to every workflow here:

### Start from a template

The CI workflows have starter templates. Each template lists every input with
its default and example values.
The workflows have starter templates: SciFY Laravel CI, SciFY Node CI and SciFY
Security. Each template lists every input with its default and example values.

1. Open your repository's **Actions** tab and click **New workflow**.
2. Under "By SciFY", pick **SciFY Laravel CI** or **SciFY Node CI**.
2. Under "By SciFY", pick **SciFY Laravel CI**, **SciFY Node CI** or **SciFY Security**.
3. Uncomment and change only the inputs that you need.
4. Commit the file.

You can also copy [`laravel-ci.yml`](../../workflow-templates/laravel-ci.yml) or
[`node-ci.yml`](../../workflow-templates/node-ci.yml) from `workflow-templates/`
You can also copy [`laravel-ci.yml`](../../workflow-templates/laravel-ci.yml),
[`node-ci.yml`](../../workflow-templates/node-ci.yml) or
[`security.yml`](../../workflow-templates/security.yml) from `workflow-templates/`
by hand. Replace `$default-branch` with `main`.

### The CI model
Expand Down Expand Up @@ -296,7 +297,7 @@ npm-only and PHP-only repositories.

| Job | What it checks |
| --- | --- |
| `Secrets` | Committed `.env` files anywhere in the repository, and Gitleaks over the full git history. Examples, `.env.testing`, `.env.ci` and templates (`.dist`, `.sample`, `.template`, `.tpl`, `.j2`, `.jinja`, `.jinja2`) are allowed |
| `Secrets` | Committed `.env` files anywhere in the repository, and Gitleaks. On a pull request, Gitleaks scans only the pull request's commits. On push and schedule, it scans the full git history. Examples, `.env.testing`, `.env.ci` and templates (`.dist`, `.sample`, `.template`, `.tpl`, `.j2`, `.jinja`, `.jinja2`) are allowed |
| `Dev tool configs` | Script files and suspicious commands in `.vscode`, `.claude`, `.cursor` and `.idea`. See [`scan-dev-configs`](../actions/scan-dev-configs/README.md) |
| `npm supply chain hardening` | `.npmrc` settings and lockfile. See [`verify-npm-hardening`](../actions/verify-npm-hardening/README.md) |
| `Dependency audit` | `composer audit --locked` and `npm audit` against the lock files. No install is needed |
Expand All @@ -306,13 +307,18 @@ npm-only and PHP-only repositories.
| `working-directory` | `.` | `frontend`, `apps/web`. The npm hardening and audit checks run there |
| `php-version` | `'8.4'` | `'8.3'` |
| `composer-abandoned` | `report` (list, do not fail) | `ignore`, `fail` |
| `gitleaks-full-history` | `false` (pull requests scan their own commits) | `true` (every run scans the full history) |
| `npm-min-release-age` | `'7'` | `'14'` (days; 7 or more) |
| `npm-audit-level` | `high` | `low`, `moderate`, `critical` |
| `strict-dev-configs` | `false` (warn only) | `true` (fail on suspicious commands) |
| `allowed-dev-scripts` | `''` (no scripts allowed) | `.claude/hooks/*.sh` (one glob per line; `*` also matches `/`) |

Run it on pull requests and once a week. The weekly run finds new advisories
for dependencies that did not change.

The weekly run also scans the full git history with Gitleaks, so it finds a
secret that reached `main` without a pull request.

In a public repository, GitHub disables scheduled workflows after 60 days
without repository activity, and it sends only an email. After a quiet period,
check the **Actions** tab and enable the workflow again:
Expand Down Expand Up @@ -356,6 +362,7 @@ jobs:
| Browser tests also run in `Backend tests` (Laravel) | Exclude the browser suite in `test-command`, for example `vendor/bin/pest --exclude-testsuite=Browser`. |
| `Environment files are committed to the repository` | A real env file, such as `.env` or `.env.production`, is committed. Remove it and rotate its secrets. A template must end in `.example`, `.dist`, `.sample`, `.template`, `.tpl`, `.j2`, `.jinja` or `.jinja2`. |
| `Found 1 abandoned package` fails the `Dependency audit` job | The caller sets `composer-abandoned: fail`. Replace the package, or set `composer-abandoned: report`. |
| `leaks found` in the `Secrets` job | Gitleaks found a secret. Rotate it first: removing it from the code does not remove it from the git history. If the finding is a false positive, add its fingerprint (printed in the log, for example `abc123:config/app.php:generic-api-key:12`) as one line to `.gitleaksignore` in the repository root. |
| The weekly security run stopped | GitHub disables scheduled workflows in a public repository after 60 days without activity. Open the workflow in the **Actions** tab and click **Enable workflow**. |
| `Script files found in dev tool directories` | A script file is in `.vscode`, `.claude`, `.cursor` or `.idea`. Remove it, or review it and add it to `allowed-dev-scripts`. |
| PHPStan or Rector re-analyse every file on each run | `analysis-cache-paths` does not match `tmpDir` in `phpstan.neon` or `cacheDirectory` in `rector.php`. |
Expand Down
32 changes: 27 additions & 5 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
# uses: scify/.github/.github/workflows/security.yml@v0.1
#
# Jobs, all independent:
# secrets committed .env files, Gitleaks over the full git history
# secrets committed .env files; Gitleaks over the pull request commits,
# or the full history on push and schedule
# dev-configs scripts and suspicious commands in .vscode/.claude/.cursor/.idea
# (scan-dev-configs action; allow reviewed scripts with allowed-dev-scripts)
# npm-hardening .npmrc and lockfile checks (verify-npm-hardening action)
Expand Down Expand Up @@ -44,6 +45,14 @@ on:
description: Fail on suspicious commands in dev tool configs. Default only warns.
type: boolean
default: false
gitleaks-full-history:
description: 'Scan the full git history on pull requests too. By default a pull request scans only its own commits; push and schedule runs always scan the full history. One of: true, false'
type: boolean
default: false
npm-min-release-age:
description: "Lowest accepted min-release-age in .npmrc, in days. 7 or more. Example: '14'"
type: string
default: '7'
allowed-dev-scripts:
description: "Newline-separated glob patterns of reviewed script files allowed in dev tool directories. `*` also matches `/`. Example: .claude/hooks/*.sh"
type: string
Expand Down Expand Up @@ -92,17 +101,29 @@ jobs:
tar -xzf gitleaks.tar.gz gitleaks
rm gitleaks.tar.gz

# Gitleaks also reads .gitleaksignore (fingerprints of accepted findings)
# from the repository root by itself.
- name: Run Gitleaks
env:
EVENT: ${{ github.event_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
FULL_HISTORY: ${{ inputs.gitleaks-full-history }}
run: |
config=""
args=(git --redact --no-banner)
if [ -f .gitleaks.toml ]; then
config="--config .gitleaks.toml"
args+=(--config .gitleaks.toml)
echo "Using repository .gitleaks.toml"
else
echo "No .gitleaks.toml, using the built-in rules"
fi
# shellcheck disable=SC2086
./gitleaks git --redact --no-banner $config .
if [ "$EVENT" = pull_request ] && [ "$FULL_HISTORY" != true ]; then
echo "Scanning the pull request commits ${BASE_SHA:0:7}..${HEAD_SHA:0:7}"
args+=("--log-opts=--no-merges ${BASE_SHA}..${HEAD_SHA}")
else
echo "Scanning the full git history"
fi
./gitleaks "${args[@]}" .

dev-configs:
name: Dev tool configs
Expand Down Expand Up @@ -160,6 +181,7 @@ jobs:
uses: ./.scify-github/.github/actions/verify-npm-hardening
with:
working-directory: ${{ inputs.working-directory }}
min-age: ${{ inputs.npm-min-release-age }}

- name: No package.json
if: hashFiles(format('{0}/package.json', inputs.working-directory)) == ''
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ deployment secrets, so they will live in a separate private repository.
| --- | --- | --- |
| `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `PULL_REQUEST_TEMPLATE.md`, `ISSUE_TEMPLATE/` | Default community health files | Automatic. Applies to every scify repository that has no file of its own. |
| `profile/README.md` | Organisation profile page | Automatic. Shown on https://github.com/scify. |
| `workflow-templates/` | Starter workflows | Actions tab → New workflow → "By SciFY". The developer gets a copy. Templates exist for Laravel CI and Node CI. |
| `workflow-templates/` | Starter workflows | Actions tab → New workflow → "By SciFY". The developer gets a copy. Templates exist for Laravel CI, Node CI and Security. |
| `.github/workflows/*.yml` | Reusable workflows (`workflow_call`) | Called with `uses: scify/.github/.github/workflows/<name>.yml@v0.1`. One implementation, shared by all callers. |
| `.github/actions/*/` | Composite actions | Called as a step with `uses: scify/.github/.github/actions/<name>@v0.1`. Each folder has its own README. |
| `templates/dependabot-*.yml` | Dependabot configuration | Manual copy to `.github/dependabot.yml`. GitHub has no default mechanism for Dependabot. |
Expand All @@ -42,7 +42,8 @@ To use them in your application, read the
lists every input with example values, and gives recipes and troubleshooting.

The quickest start for CI: open your repository's **Actions** tab, click
**New workflow**, and pick **SciFY Laravel CI** or **SciFY Node CI**.
**New workflow**, and pick **SciFY Laravel CI** or **SciFY Node CI**. Add
**SciFY Security** the same way.

## Dependabot

Expand Down
7 changes: 7 additions & 0 deletions workflow-templates/security.properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "SciFY Security",
"description": "Committed env files, Gitleaks, dev tool configs, npm hardening, composer audit and npm audit through the shared scify/.github workflow.",
"iconName": "octicon shield-check",
"categories": ["Security"],
"filePatterns": ["composer.json$", "package.json$"]
}
30 changes: 30 additions & 0 deletions workflow-templates/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Security checks for a SciFY repository.
# The logic lives in scify/.github. Change inputs here, not the steps.
# Guide: https://github.com/scify/.github/blob/main/.github/workflows/README.md#security
#
# Each commented-out input shows its default. Uncomment a line only to change it.
# The "e.g." comment shows other accepted values.
# To change an input, also uncomment the `with:` line.
name: Security

on:
pull_request:
# The weekly run finds new advisories and scans the full git history.
schedule:
- cron: '0 11 * * 1'

permissions:
contents: read

jobs:
security:
uses: scify/.github/.github/workflows/security.yml@v0.1
# with:
# working-directory: . # e.g. frontend (the folder with package.json)
# php-version: '8.4' # e.g. '8.3' (runs composer audit)
# composer-abandoned: report # e.g. fail, ignore
# npm-audit-level: high # e.g. moderate, critical
# npm-min-release-age: '7' # e.g. '14' (days, 7 or more)
# gitleaks-full-history: false # true: pull requests scan the full history too
# strict-dev-configs: false # true: fail on suspicious commands in dev tool configs
# allowed-dev-scripts: '' # e.g. .claude/hooks/*.sh (one glob per line)
Loading