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: 19 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# CODEOWNERS for Pinewood One
# These owners are requested for review when someone opens a PR touching
# matching paths. See:
# https://docs.github.com/articles/about-code-owners

# Default owner for everything in the repo.
* @AdamEXu

# Top-level applications.
/frontend/ @AdamEXu
/backend/ @AdamEXu

# Security-sensitive backend areas (extra scrutiny on review).
/backend/auth/ @AdamEXu
/backend/db/ @AdamEXu
/backend/services/scraper/ @AdamEXu

# Repository automation and policy.
/.github/ @AdamEXu
50 changes: 50 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Bug report
description: Report a problem with Pinewood One
labels:
- bug
body:
- type: markdown
attributes:
value: >-
Thanks for taking the time to file a bug! For **security
vulnerabilities**, do not use this form — report privately via a GitHub
security advisory (see .github/SECURITY.md).
- type: dropdown
id: area
attributes:
label: Area
description: Which part of the app is affected?
options:
- frontend
- backend
- scraper
- convex
- other
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A clear description of the bug, including what you expected to happen.
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: How can we reproduce the problem?
placeholder: |
1. Go to '...'
2. Click on '...'
3. See error
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: Browser/OS, and whether this is local dev or a deployment. Do NOT paste secrets, tokens, or real student data.
placeholder: e.g. Chrome 130 on macOS 14, local dev
validations:
required: false
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://github.com/Pinewood-Tech-Club/one/security/advisories/new
about: >-
Please do NOT file public issues for security problems. Report
vulnerabilities privately via a GitHub security advisory. See
.github/SECURITY.md for details.
35 changes: 35 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Feature request
description: Suggest an idea or improvement for Pinewood One
labels:
- enhancement
body:
- type: markdown
attributes:
value: Thanks for suggesting an improvement! Please describe the problem before the solution.
- type: textarea
id: problem
attributes:
label: Problem / motivation
description: What problem are you trying to solve? Why does it matter?
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed solution
description: Describe what you'd like to happen. Include alternatives you've considered.
validations:
required: true
- type: dropdown
id: area
attributes:
label: Area
description: Which part of the app does this affect?
options:
- frontend
- backend
- scraper
- convex
- other
validations:
required: true
65 changes: 65 additions & 0 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Security Policy

Pinewood One handles **sensitive student data** — Schoology grades, schedules,
and assignments — as well as **OAuth tokens** and session credentials. We take
security reports seriously and appreciate responsible disclosure.

## Reporting a vulnerability

**Please do not open a public GitHub issue for security problems.** Public
issues disclose the vulnerability before it can be fixed.

**Primary channel — GitHub private security advisory:**

> https://github.com/Pinewood-Tech-Club/one/security/advisories/new

Use the "Report a vulnerability" button on that page to open a private advisory.
This keeps the report confidential and lets us collaborate on a fix.

If you cannot use the advisory workflow, contact a maintainer
(**@AdamEXu**) privately through GitHub and ask for a secure channel. Please do
not post vulnerability details in public comments, discussions, or issues.

### What to include

- A description of the vulnerability and its impact.
- Steps to reproduce (proof of concept if possible).
- Affected component(s) and any relevant version/commit.
- Any suggested remediation, if you have one.

## Scope

We are especially interested in reports affecting:

- **Authentication & sessions** — Google OAuth login, session issuance,
expiration, and cookie handling.
- **OAuth token storage** — encryption at rest (Fernet), token handling, and
any path where tokens could leak (logs, error responses).
- **Scraper** (`backend/services/scraper/`) — server-side request forgery
(SSRF) via scraped URLs, and job-lease integrity / race conditions.
- **Chat SSE** — the server-sent-events chat stream (authorization, data
leakage across users).
- **IDOR / broken access control** — any endpoint returning user data without
verifying ownership.

## Please avoid

To protect real users while testing, please **do not**:

- Scan, probe, or attack the **production Cloudflare tunnel** or any live
deployment.
- Access, exfiltrate, or modify **real student data** or another person's
account.
- Run automated scanners against production infrastructure.

Test against a local development instance whenever possible. If you believe a
finding can only be demonstrated against production, describe it in the private
advisory and we will help reproduce it safely.

## Our commitment

- We will acknowledge your report as soon as we can.
- We will keep you informed as we investigate and remediate.
- We will credit reporters who wish to be acknowledged, once a fix is released.

Thank you for helping keep Pinewood One and its users safe.
40 changes: 40 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
version: 2
updates:
# Frontend JavaScript/TypeScript dependencies (Next.js app)
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "frontend"
groups:
minor-and-patch:
update-types:
- "minor"
- "patch"

# Backend Python dependencies (Flask app)
- package-ecosystem: "pip"
directory: "/backend"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "backend"
groups:
minor-and-patch:
update-types:
- "minor"
- "patch"

# GitHub Actions workflow dependencies
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
- "ci"
38 changes: 38 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!--
Thanks for contributing to Pinewood One! Please fill out this template.
PRs with an incomplete security checklist will not be merged.
-->

## What & why

<!-- What does this PR change, and why? Link any related issues. -->

## Area

<!-- Check all that apply -->

- [ ] Frontend
- [ ] Backend
- [ ] Scraper
- [ ] Convex
- [ ] Infra / tooling

## How tested

<!-- Describe how you verified this change (manual steps, endpoints hit, etc.). -->

## Security checklist

<!-- Every box must be checked (or marked N/A with a reason) before merge. -->

- [ ] Endpoints returning user data enforce **ownership / authorization** (no IDOR — a user cannot read another user's data).
- [ ] `@auth_required` is applied to routes that need authentication.
- [ ] No **SSRF**: any outbound/scraped URL is validated (scheme + host) before it is fetched.
- [ ] No secrets committed — no `.env`, `*.db`, keys, or credentials in the diff.
- [ ] Flask **debug mode is not forced on** in a production code path.
- [ ] OAuth **tokens stay encrypted** at rest and are **never logged** or returned in responses.

## Checks

- [ ] `cd frontend && pnpm lint` passes.
- [ ] Backend still starts and affected endpoints work (`make dev-backend`).
46 changes: 46 additions & 0 deletions .github/workflows/backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: backend

on:
pull_request:
paths:
- "backend/**"
- ".github/workflows/backend.yml"
push:
branches:
- main
- dev
paths:
- "backend/**"

jobs:
backend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install ruff
run: pip install ruff==0.9.6

- name: Ruff lint
run: ruff check .

# NOTE: `ruff format --check .` is intentionally omitted for now.
# A first-time format pass would reformat ~46 files, which does not
# belong in a security-focused PR. Enable it as a follow-up once a
# dedicated formatting commit lands.

- name: Byte-compile
run: python -m compileall -q -x "env/" .

- name: Install test dependencies
run: pip install -r requirements.txt -r requirements-test.txt

- name: Run tests
run: python -m pytest
37 changes: 37 additions & 0 deletions .github/workflows/bandit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Bandit

on:
push:
branches:
- main
pull_request:
branches:
- main

permissions:
security-events: write
contents: read

jobs:
bandit:
name: Bandit Python SAST
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Bandit
run: pip install 'bandit[sarif]'

- name: Run Bandit
run: bandit -r backend -x backend/env,backend/__pycache__ -f sarif -o bandit.sarif || true

- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: bandit.sarif
47 changes: 47 additions & 0 deletions .github/workflows/ci-frontend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI Frontend

on:
pull_request:
branches: [main]
paths:
- 'frontend/**'
- '.github/workflows/ci-frontend.yml'

jobs:
frontend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: 10

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: frontend/pnpm-lock.yaml

- name: Install dependencies
run: pnpm install --frozen-lockfile

# Hard gate: the type checker is clean today and must stay clean.
- name: Typecheck
run: pnpm typecheck

# Non-blocking ratchet: ~71 pre-existing eslint violations. Runs for
# visibility; flip to a hard gate once the backlog is burned down.
- name: Lint
run: pnpm lint
continue-on-error: true

# Non-blocking for now: `next build` needs NEXT_PUBLIC_* env configured
# as repo secrets/vars to pass reliably. Make it a hard gate once those
# are wired up in repo settings.
- name: Build
run: pnpm build
continue-on-error: true
Loading
Loading