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
6 changes: 6 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Security and release changes require the repository owner when protections apply.
/.github/ @DavidHruby1
/requirements*.txt @DavidHruby1
/screamer.spec @DavidHruby1
/SECURITY.md @DavidHruby1
/docs/SECURITY.md @DavidHruby1
46 changes: 36 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ permissions:
jobs:
# Every application module must byte-compile and import on a non-Windows host.
compile:
timeout-minutes: 15
name: compile (ubuntu / py3.12)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- run: python -m compileall src/ tests/ .github/scripts/
Expand All @@ -44,15 +47,18 @@ jobs:

# Full test suite on the target platform.
test:
timeout-minutes: 30
name: test (windows / py${{ matrix.python-version }})
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
cache: pip
Expand All @@ -68,11 +74,14 @@ jobs:
run: python -m unittest discover -s tests -v

build:
timeout-minutes: 40
name: build (windows / py3.12)
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
cache: pip
Expand All @@ -90,24 +99,41 @@ jobs:
}

lint:
timeout-minutes: 10
name: lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- run: pip install ruff==0.15.15
- run: ruff check src/ tests/ .github/scripts/
- run: ruff format --check src/ tests/ .github/scripts/

audit:
timeout-minutes: 15
name: pip-audit (CVE scan)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- run: pip install pip-audit
- run: pip-audit -r requirements.txt -r requirements-build.txt

dependency-review:
name: dependency-review
if: ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: low
comment-summary-in-pr: never
14 changes: 10 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@ on:

permissions:
contents: read
security-events: write

jobs:
analyze:
timeout-minutes: 30
name: analyze (python)
permissions:
contents: read
security-events: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: github/codeql-action/init@v3
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4
with:
languages: python
- uses: github/codeql-action/analyze@v3
queries: security-extended
- uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4
with:
category: "/language:python"
15 changes: 9 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ permissions:

jobs:
plan:
timeout-minutes: 20
if: >-
${{ github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
Expand All @@ -28,7 +29,7 @@ jobs:
tag: ${{ steps.plan.outputs.tag }}
sha: ${{ steps.plan.outputs.sha }}
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
Expand All @@ -41,17 +42,18 @@ jobs:
run: python .github/scripts/release.py plan

build:
timeout-minutes: 40
needs: plan
if: ${{ needs.plan.outputs.tag != '' }}
runs-on: windows-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.plan.outputs.sha }}
persist-credentials: false
- uses: actions/setup-python@v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
cache: pip
Expand All @@ -77,7 +79,7 @@ jobs:
"$hash $zip" | Out-File -FilePath "$zip.sha256" -Encoding ascii
"ASSET_ZIP=$zip" | Out-File -FilePath $env:GITHUB_ENV -Append
"ASSET_SHA=$zip.sha256" | Out-File -FilePath $env:GITHUB_ENV -Append
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-assets
path: |
Expand All @@ -87,16 +89,17 @@ jobs:
retention-days: 7

publish:
timeout-minutes: 10
needs: [plan, build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.plan.outputs.sha }}
persist-credentials: false
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: release-assets
path: release-assets
Expand Down
13 changes: 13 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Security Policy

Security fixes are maintained for the latest published release. Update to the latest
release before reporting a vulnerability.

Report vulnerabilities privately through [GitHub private vulnerability reporting](https://github.com/DavidHruby1/screamer/security/advisories/new).
Include the affected version, impact and a minimal reproduction. Do not put API keys,
recordings, transcripts or other private data into public issues or pull requests.
If a credential has been exposed, revoke it at its provider immediately; deleting a
file or commit does not revoke the credential.

Repository controls and their operational requirements are documented in
[Repository Security](docs/SECURITY.md).
9 changes: 6 additions & 3 deletions docs/RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ file; GitHub generates the release notes.
The Windows job runs unit tests, builds the onedir executable, and produces the versioned
ZIP and `.sha256`. Only a separate publication job receives `contents: write`; it
checks the tested SHA, checksum, executable in the ZIP and GitHub asset digests, then
publishes the draft. It never runs dependency installation or the build with write
publishes the draft. New releases become immutable at publication, protecting their
assets and tags from later replacement. Older releases are not locked retroactively.
It never runs dependency installation or the build with write
permission. A tag may exist before publication if asset upload fails; this is not a
public release. The workflow accepts a matching draft/tag on retry but refuses to
overwrite an asset or tag with a mismatched SHA/digest.
Expand All @@ -36,8 +38,9 @@ planning inspects every paginated release page.
release or reuse a version that users may already have downloaded.

This is automation after **human review of the code PR**, not automated bypass of
branch protection. There is no signing certificate or supply-chain attestation: a
checksum detects transfer corruption but is not proof of provenance. CI checks the
branch protection. There is no Windows code-signing certificate; the checksum detects transfer corruption
and does not authenticate the desktop executable. GitHub release immutability protects
newly published release assets and tags against later replacement. CI checks the
build output exists; it does not run the packaged app with a real microphone. Windows
DPAPI, Win32 input and the downloadable ZIP should be smoke-tested on Windows when
shipping a significant desktop change.
74 changes: 74 additions & 0 deletions docs/SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Repository Security

This project is public. Visitors can read and fork it, but cannot push to this
repository without an authorized credential. Only the owner currently has write
access. GitHub account security, authorized apps and the owner's computers remain
part of the trust boundary; repository settings cannot protect a compromised admin.
Use 2FA with a passkey or security key and review authorized apps and SSH keys.

## Branch protection and administrator access

`main` requires a pull request, one approving review, dismissal of stale approvals,
resolved conversations, an up-to-date branch and the following GitHub Actions checks:

- `compile (ubuntu / py3.12)`
- `test (windows / py3.11)`
- `test (windows / py3.12)`
- `build (windows / py3.12)`
- `lint (ruff)`
- `pip-audit (CVE scan)`
- `analyze (python)`
- `dependency-review`

Required checks are tied to the GitHub Actions app. CODEOWNERS assigns workflow,
release and dependency changes to `@DavidHruby1`; applicable PRs require code owner
review. Force pushes and branch deletion are disabled in the branch rule.
A separate CodeQL ruleset rejects PRs with any new CodeQL alert, rather than merely
requiring the analysis job to finish. CodeQL runs the `security-extended` query suite.
That ruleset explicitly allows the administrator role to bypass it at any time.

**Administrator bypass is intentional and must remain enabled.** The owner can merge
their own PRs without another reviewer. Do not enable `enforce_admins`, remove this
exception through a ruleset, or add an environment approval that prevents the owner
from publishing. All checks should still be inspected before an admin merge.

## GitHub Actions

- All external fork contributors require approval before their workflows run.
Inspect changes to workflows, dependency files and executable scripts before
approving. Approval permits code execution on GitHub's temporary runner.
- The repository allows GitHub-owned actions only and requires full commit SHA pins.
Every action in the workflow files has an upstream SHA with a version comment.
Dependabot maintains these pins through reviewed PRs.
- The default token is read-only and cannot approve PRs. Checkouts do not persist
credentials. CodeQL receives only its additional security reporting permission;
only the release publication job receives `contents: write`.
- Jobs have explicit time limits. There are no self-hosted runners or stored
repository Actions secrets.
- Dependency review rejects newly introduced dependencies with known vulnerabilities
of low severity or higher. `pip-audit` also checks the resolved Python dependency
set. These checks do not prove that an unknown vulnerability or malicious package
is absent.

When adding an action, review its upstream source and permissions, pin the full SHA,
and keep the version comment so Dependabot can update it. An older open PR containing
unpinned actions needs to incorporate the updated `main` before its checks can rerun
under the SHA policy. Administrator merge access remains available.

## Alerts and releases

Dependabot alerts and security update PRs are enabled independently of weekly version
update PRs. Secret scanning and push protection remain enabled. Review and remediate
alerts; an empty alert list is not proof that no secret or vulnerability exists.
Private vulnerability reporting is enabled; see [Security Policy](../SECURITY.md).

Future releases are immutable after publication. The release workflow builds from a
successful CI push to this repository's `main`, waits for CodeQL on the same commit,
and gives build jobs no write token. It uploads and checks assets while the release
is a draft, then publishes it. Immutability does not retroactively lock old releases.
See [Release Operations](RELEASES.md) for retry and recovery procedures.

GitHub repository policies are configured through repository settings and are not
applied by checking out these files. After changing them, read the settings back and
confirm the administrator exception is still present. Do not grant extra token
permissions or disable security checks just to make a dependency update pass.
Loading