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
5 changes: 5 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ jobs:
- run: pip install -e ".[docs]"
- run: cp CHANGELOG.md docs/changelog.md
- run: mkdocs build --strict
# Tries to switch Pages on. The built-in token is not always allowed to; if this step cannot,
# enable Settings > Pages > Source: GitHub Actions once, by hand.
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
continue-on-error: true
with:
enablement: true
- uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
with:
path: site
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Prepare release

# Run from the Actions tab: bumps the version, rolls the changelog, tags, and starts the release.
on:
workflow_dispatch:
inputs:
version:
description: Version to release, for example 1.0.0
required: true

permissions:
contents: read

jobs:
prepare:
runs-on: ubuntu-latest
permissions:
contents: write
actions: write
env:
VERSION: ${{ inputs.version }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
fetch-depth: 0
- name: Bump the version and the changelog
run: python3 scripts/bump_release.py "$VERSION"
- name: Commit and tag
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -am "Release $VERSION"
git tag "v$VERSION"
git push origin HEAD "v$VERSION"
# Pushes made with the built-in token do not start other workflows, so start it explicitly.
- name: Start the release workflow
run: gh workflow run release.yml --ref "v$VERSION"
29 changes: 29 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name: Release
on:
push:
tags: ["v*"]
# Started by the prepare-release workflow, whose tag push cannot trigger this one itself.
workflow_dispatch:

permissions:
contents: read
Expand Down Expand Up @@ -44,7 +46,10 @@ jobs:
with:
name: dist
path: dist/
# With no PYPI_API_TOKEN secret this uses trusted publishing (OIDC).
- uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
with:
password: ${{ secrets.PYPI_API_TOKEN }}

github-release:
needs: pypi
Expand Down Expand Up @@ -98,3 +103,27 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

action-tag:
needs: github-release
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
OWNER: ${{ github.repository_owner }}
steps:
- name: Move the major tag of the action repository
run: |
if [ -z "$GH_TOKEN" ]; then
echo "::notice::ACTION_REPO_TOKEN is not set, skipping the action tags"
exit 0
fi
version="${GITHUB_REF_NAME#v}"
major="v${version%%.*}"
gh auth setup-git
git clone "https://github.com/$OWNER/devshield-action.git" out
cd out
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -f "$GITHUB_REF_NAME"
git tag -f "$major"
git push -f origin "$GITHUB_REF_NAME" "$major"
46 changes: 46 additions & 0 deletions .github/workflows/sync-action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Sync action

# Publishes packaging/devshield-action to the ByteGigs-Labs/devshield-action repository.
# It needs a secret named ACTION_REPO_TOKEN (a personal access token with the repo scope).
# Without the secret this workflow does nothing, and the action still works from this
# repository as ByteGigs-Labs/DevShield-CLI/packaging/devshield-action@main.
on:
push:
branches: [main]
paths: ["packaging/devshield-action/**", ".github/workflows/sync-action.yml"]
workflow_dispatch:

permissions:
contents: read

jobs:
sync:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
OWNER: ${{ github.repository_owner }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Sync
run: |
if [ -z "$GH_TOKEN" ]; then
echo "::notice::ACTION_REPO_TOKEN is not set, skipping the action repository sync"
exit 0
fi
target="$OWNER/devshield-action"
gh repo view "$target" > /dev/null 2>&1 \
|| gh repo create "$target" --public --description "GitHub Action for DevShield"
gh auth setup-git
git clone "https://github.com/$target.git" out
cp packaging/devshield-action/action.yml packaging/devshield-action/README.md out/
cd out
git checkout -B main
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
if git diff --cached --quiet; then
echo "Already up to date"
else
git commit -m "Sync from DevShield-CLI $GITHUB_SHA"
git push origin main
fi
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ All notable changes to this project are documented here. The format follows
- Plugin system: rules from third-party packages through the `devshield.rules` entry point,
`devshield plugins list`, failure isolation, `devshield.testing.run_rule` and a plugin guide.
- An example plugin in `examples/devshield-plugin-example`.
- Documentation site, pre-commit hooks, a Docker image and a GitHub Action template.
- Documentation site with screenshots, pre-commit hooks, a Docker image, a GitHub Action and
release automation (`Prepare release` workflow, PyPI publishing, action repository sync).

### Changed

Expand Down
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@ Upcoming:

---

# Screenshots

### Scan

<img src="https://raw.githubusercontent.com/ByteGigs-Labs/DevShield-CLI/main/docs/images/scan.svg" alt="devshield scan output: findings grouped by area with a risk score" width="820">

### HTML report

A single self-contained file with a risk gauge, search and category filters, and no external requests.

<img src="https://raw.githubusercontent.com/ByteGigs-Labs/DevShield-CLI/main/docs/images/html-report.png" alt="The HTML report with a risk gauge and a filterable findings table" width="820">

### Safe auto-fix

<img src="https://raw.githubusercontent.com/ByteGigs-Labs/DevShield-CLI/main/docs/images/fix.svg" alt="devshield fix showing a diff of the files it would create" width="820">

### Dependency vulnerabilities

<img src="https://raw.githubusercontent.com/ByteGigs-Labs/DevShield-CLI/main/docs/images/deps.svg" alt="devshield deps listing known advisories for an outdated lodash" width="820">

### Docker image inspection

<img src="https://raw.githubusercontent.com/ByteGigs-Labs/DevShield-CLI/main/docs/images/docker-scan.svg" alt="devshield docker scan results for a local image" width="820">

Regenerate them with `python scripts/gen_screenshots.py`.


# Installation

```bash
Expand Down
51 changes: 32 additions & 19 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
# Releasing

Releases are cut from `main` by pushing a tag. Everything after the tag is automated.
## The short version

## Checklist
Open **Actions, Prepare release, Run workflow** and enter the version (for example `1.0.0`).
It bumps `__version__`, turns the `[Unreleased]` changelog section into that version, commits,
tags `vX.Y.Z` and starts the `release` workflow. Make sure CI is green on `main` first.

1. Make sure CI is green on `main`, and run the performance budget: `pytest -m perf`.
2. In `CHANGELOG.md`, rename `[Unreleased]` to `[X.Y.Z] - YYYY-MM-DD` and add a fresh empty
`[Unreleased]` section above it. Update the link references if you keep any.
3. Set `__version__` in `devshield/__init__.py` to `X.Y.Z`.
4. Commit: `git commit -am "Release X.Y.Z"`, then `git tag vX.Y.Z` and `git push --follow-tags`.
You can also do it by hand: `python scripts/bump_release.py X.Y.Z`, commit, `git tag vX.Y.Z`,
`git push --follow-tags`.

The `release` workflow then:

- builds the sdist and wheel and checks that the tag matches `__version__`;
- publishes to PyPI with trusted publishing (no token is stored);
- publishes to PyPI;
- creates a GitHub release whose notes come from the matching `CHANGELOG.md` section;
- builds and pushes `ghcr.io/bytegigs-labs/devshield` tagged `X.Y.Z`, `X.Y` and `latest`.
- builds and pushes `ghcr.io/bytegigs-labs/devshield` tagged `X.Y.Z`, `X.Y` and `latest`;
- moves the `vX` and `vX.Y.Z` tags of the action repository (when `ACTION_REPO_TOKEN` is set).

The `docs` workflow redeploys the documentation site on every push to `main`.

## One-time setup

- **PyPI:** create the `devshield-cli` project (or a pending publisher) and add a trusted
publisher: owner `ByteGigs-Labs`, repository `DevShield-CLI`, workflow `release.yml`,
environment `pypi`. Create a GitHub environment named `pypi`.
- **GitHub Pages:** Settings, Pages, Source: GitHub Actions.
- **Packages:** after the first image push, make the `devshield` package public.
- **GitHub Action:** copy `packaging/devshield-action/` into a new
`ByteGigs-Labs/devshield-action` repository, tag it `v1`, and move the `v1` tag with each release.
- **Secret patterns:** `devshield update` reads `data/secret-patterns.json` from `main`.
## What configures itself

On the first push these need no manual setup: the `pypi` and `github-pages` environments (GitHub
creates them when a workflow first uses them), the docs build, the CI jobs and the release
automation above. The `docs` workflow also tries to switch GitHub Pages on.

## What GitHub or PyPI only allow you to do yourself

A workflow cannot grant itself these, so they are one-time clicks:

- **PyPI publishing.** Either add a trusted publisher (PyPI, Your projects or Publishing, add a
pending publisher: owner `ByteGigs-Labs`, repository `DevShield-CLI`, workflow `release.yml`,
environment `pypi`), or create an API token and save it as the repository secret
`PYPI_API_TOKEN`. The workflow uses the token when it exists and trusted publishing otherwise.
- **GitHub Pages**, only if the `docs` workflow could not enable it: Settings, Pages, Source:
GitHub Actions.
- **The action repository (optional).** Save a personal access token with the `repo` scope as the
secret `ACTION_REPO_TOKEN`. The `sync-action` workflow then creates
`ByteGigs-Labs/devshield-action`, keeps it in sync, and `release` moves its `v1` tag. Without it
the action works from this repository as
`ByteGigs-Labs/DevShield-CLI/packaging/devshield-action@main`.
- **Image visibility.** After the first image push, open the `devshield` package on GitHub and set
its visibility to public.

## Version numbers

Expand Down
Loading
Loading