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
43 changes: 43 additions & 0 deletions .commitlintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const Configuration = {
/*
* Resolve and load @commitlint/config-conventional from node_modules.
* Referenced packages must be installed
*/
extends: ["@commitlint/config-conventional"],
// config-conventional implements conventional commits rules as defined at https://www.conventionalcommits.org

/*
* Any rules defined here will override rules from @commitlint/config-conventional
*/
rules: {
"type-enum": [1, "always", ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test']],
"header-trim": [2, "always"],
"reference-empty": [2, "never"],
},

/*
* Array of functions that return true if commitlint should ignore the given message.
* Given array is merged with predefined functions, which consist of matchers like:
*
* - 'Merge pull request', 'Merge X into Y' or 'Merge branch X'
* - 'Revert X'
* - 'v1.2.3' (ie semver matcher)
* - 'Automatic merge X' or 'Auto-merged X into Y'
*
* To see full list, check https://github.com/conventional-changelog/commitlint/blob/master/%40commitlint/is-ignored/src/defaults.ts.
* To disable those ignores and run rules always, set `defaultIgnores: false` as shown below.
*/
ignores: [(commit) => commit === ""],
/*
* Whether commitlint uses the default ignore rules, see the description above.
*/
defaultIgnores: true,

/*
* Custom URL to show upon failure
*/
helpUrl:
"",
};

export default Configuration;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file uses ESM syntax (export default) but the repo has no package.json indicating type: module. In a default Node/commitlint setup, this will be parsed as CommonJS and fail to load. Consider switching to CommonJS (module.exports = …) or renaming to .commitlintrc.cjs (or adding the necessary Node module configuration).

Suggested change
export default Configuration;
module.exports = Configuration;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

@pablo-schmeiser pablo-schmeiser Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly don't understand this. The docs for the commitlint config were honestly pretty bad.

4 changes: 4 additions & 0 deletions .github/pr406.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
threshold: 7
dry_run: true
label: likely ai-slop
close_on_trigger: false
17 changes: 17 additions & 0 deletions .github/workflows/check_dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: 'Dependency Check'

on: [pull_request]

jobs:
dependency-review:
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: 'Checkout Repository'
uses: actions/checkout@v6
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
59 changes: 59 additions & 0 deletions .github/workflows/check_integrity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
# Build the project and use django's check command to check for common errors.
name: Check Integrity

on: [push, pull_request, workflow_dispatch, workflow_call]

jobs:
python-versions:
uses: ./.github/workflows/extract_python_versions.yml

check-integrity:
runs-on: ubuntu-latest
needs: python-versions

permissions:
contents: read
pull-requests: write
issues: write
statuses: write

strategy:
matrix:
python-version: ${{ fromJson(needs['python-versions'].outputs.versions) }}

steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .
- name: Check integrity
run: |
python src/manage.py check --deploy --fail-level=WARNING

update-readme-integrity-badges:
runs-on: ubuntu-latest
needs: [python-versions, check-integrity]
if: github.event_name == 'push' && github.ref == 'refs/heads/master'

permissions:
contents: write

steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
- name: Add integrity badges to README between comments
env:
PYTHON_VERSIONS: ${{ needs['python-versions'].outputs.versions }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: python .github/workflows/update_integrity_badges.py
- uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: 'ci: update integrity badges in README'
file_pattern: README.md
24 changes: 24 additions & 0 deletions .github/workflows/detect_ai.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: Detect AI

on:
pull_request_target:
types: [opened, reopened, synchronize, edited]

jobs:
pr406:
name: Check for AI-generated PRs
runs-on: ubuntu-latest

permissions:
contents: read
pull-requests: write

steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.ref }}
- uses: lu-zhengda/pr406@v0.1.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
config_path: .github/pr406.yml
56 changes: 56 additions & 0 deletions .github/workflows/extract_python_versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
name: Extract Python Versions

description: Extract Python versions from pyproject.toml classifiers and output as JSON array for use in other workflows.

on:
workflow_call:
outputs:
versions:
description: JSON array of Python versions from pyproject.toml classifiers
value: ${{ jobs.extract.outputs.versions }}

jobs:
extract:
runs-on: ubuntu-latest
outputs:
versions: ${{ steps.get.outputs.versions }}

steps:
- uses: actions/checkout@v6

- name: Read versions from pyproject.toml
id: get
run: |
python - <<'PY'
import json
import re
import tomllib
from pathlib import Path

pyproject = Path('pyproject.toml')
if not pyproject.exists():
raise SystemExit('pyproject.toml not found')

data = tomllib.loads(pyproject.read_text(encoding='utf-8'))
classifiers = data.get('project', {}).get('classifiers', [])

pattern = re.compile(r'^Programming Language :: Python :: (\d+\.\d+)$')
versions = sorted(
{
match.group(1)
for classifier in classifiers
if (match := pattern.match(classifier))
},
key=lambda version: tuple(map(int, version.split('.'))),
)

if not versions:
raise SystemExit(
'No Python version classifiers found in pyproject.toml under project.classifiers'
)

output = Path(__import__('os').environ['GITHUB_OUTPUT'])
output.write_text(f"versions={json.dumps(versions)}\n", encoding='utf-8')
print(f'Extracted versions: {", ".join(versions)}')
PY
51 changes: 51 additions & 0 deletions .github/workflows/owasp-noir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
name: OWASP Noir Security Analysis

on: [push, pull_request, workflow_dispatch, workflow_call]

jobs:
noir-analysis:
runs-on: ubuntu-latest

permissions:
contents: read
pull-requests: write
issues: write

steps:
- uses: actions/checkout@v6

- name: Run OWASP Noir
id: noir
uses: owasp-noir/noir@main
with:
base_path: '.'
techs: 'django'
passive_scan: 'true'
passive_scan_severity: 'medium'
use_all_taggers: 'true'
include_path: 'true'
format: 'markdown-table'
output_file: 'noir_results.md'

# Optional: Higher concurrency can speed up the analysis but may increase resource usage
# and could lead to OOM errors on larger codebases.
# Adjust as needed. 20 is reasonable for default GitHub runners.
concurrency: '20'

- name: Upload Noir Reports
uses: actions/upload-artifact@v7
if: always() # Always upload results even if vulnerabilities are found
with:
name: noir-results
path: noir_results.md

- name: Comment Noir Report on PR
if: github.event_name == 'pull_request' && steps.noir.outputs.report != ''
uses: peter-evans/create-or-update-comment@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
body: |
## OWASP Noir Security Analysis Report
${{ steps.noir.outputs.report }}
42 changes: 42 additions & 0 deletions .github/workflows/super-linter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
# This runs classic linters on the codebase, but also uses some more advanced tools.
# Also uses: Trivy, GitLeaks, codespell, pre-commit, spectral, jscpd and more.
# See https://github.com/marketplace/actions/super-linter for more details.
name: Super-Linter

on: [push, pull_request, workflow_dispatch]

jobs:
build:
name: Super-Linter
runs-on: ubuntu-latest

permissions:
# contents permission to clone the repository
contents: read
packages: read
# issues and pull-requests permissions to write results as pull
# request comments. Omit them if you don't need summary comments
issues: write
pull-requests: write
# To report GitHub Actions status checks. Omit if you don't need
# to update commit status
statuses: write

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
# super-linter needs the full git history to get the
# list of files that changed across commits
fetch-depth: 0
persist-credentials: false

- name: Super-linter
uses: super-linter/super-linter/slim@v8.5.0 # x-release-please-version
env:
# To report GitHub Actions status checks
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# To only check files that changed across commits
VALIDATE_ALL_CODEBASE: false

48 changes: 48 additions & 0 deletions .github/workflows/update_integrity_badges.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import json
import os
import sys
from pathlib import Path

readme = Path('README.md')
start_marker = '<!-- Start Integrity Badges -->'
end_marker = '<!-- End Integrity Badges -->'

content = readme.read_text(encoding='utf-8')
if start_marker not in content or end_marker not in content:
print('README markers were not found.', file=sys.stderr)
sys.exit(1)

raw_versions = os.environ.get('PYTHON_VERSIONS', '')

try:
parsed_versions = json.loads(raw_versions)
except json.JSONDecodeError as exc:
print(f'PYTHON_VERSIONS must be a JSON array of strings: {exc}', file=sys.stderr)
sys.exit(1)

if not isinstance(parsed_versions, list) or not all(
isinstance(version, str) for version in parsed_versions
):
print('PYTHON_VERSIONS must be a JSON array of strings.', file=sys.stderr)
sys.exit(1)

versions = [version.strip() for version in parsed_versions if version.strip()]
if not versions:
print('PYTHON_VERSIONS JSON array is empty.', file=sys.stderr)
sys.exit(1)

repository = os.environ['GITHUB_REPOSITORY']
workflow = 'check_integrity.yml'

badges = [
f'[![Python {version}]'
f'(https://img.shields.io/badge/Python-{version}-3776AB?logo=python&logoColor=white)]'
f'(https://github.com/{repository}/actions/workflows/{workflow})'
for version in versions
]

start_index = content.index(start_marker) + len(start_marker)
end_index = content.index(end_marker)
replacement = '\n' + '\n'.join(badges) + '\n'
updated = content[:start_index] + replacement + content[end_index:]
readme.write_text(updated, encoding='utf-8')
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,8 @@ repos:
rev: v8.30.0
hooks:
- id: gitleaks
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: <latest tag>
hooks:
- id: commitlint
stages: [commit-msg]
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Shiftings

[![Super-Linter](https://github.com/<OWNER>/<REPOSITORY>/actions/workflows/<WORKFLOW_FILE_NAME>/badge.svg)](https://github.com/marketplace/actions/super-linter)
<!-- Start Integrity Badges -->
<!-- End Integrity Badges -->

This is a simple shift management system. Built and maintained by students from the self-governed student dormitory [HaDiKo](https://www.hadiko.de/).

## Description
Expand Down