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
82 changes: 82 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Bug report
description: Report a reproducible problem in ContenderOS
title: "[Bug]: "
labels:
- bug
body:
- type: markdown
attributes:
value: |
Thanks for helping improve ContenderOS. Use synthetic or redacted examples only.
Security vulnerabilities and personal-data exposures belong in the private
**Report a vulnerability** flow, not a public issue.

- type: checkboxes
id: preflight
attributes:
label: Before submitting
options:
- label: I searched existing issues for this problem.
required: true
- label: I removed credentials, real CV data, contact details, cookies, and account identifiers.
required: true
- label: This is not a security vulnerability or personal-data exposure.
required: true

- type: textarea
id: summary
attributes:
label: Problem
description: What went wrong, and what user-facing impact did it have?
validations:
required: true

- type: textarea
id: reproduction
attributes:
label: Minimal reproduction
description: Give the smallest reliable sequence using synthetic data.
placeholder: |
1. Start ...
2. Open ...
3. Observe ...
validations:
required: true

- type: textarea
id: expected
attributes:
label: Expected behaviour
validations:
required: true

- type: textarea
id: actual
attributes:
label: Actual behaviour
validations:
required: true

- type: input
id: version
attributes:
label: Version or commit
description: Release, branch, or commit SHA where the problem occurs.
placeholder: main at abc1234
validations:
required: true

- type: textarea
id: environment
attributes:
label: Environment
description: OS, browser, Node/Python versions, and deployment type if relevant.
validations:
required: true

- type: textarea
id: logs
attributes:
label: Sanitised logs or screenshots
description: Optional. Redact secrets, URLs with tokens, and all personal data.
render: shell
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Report a security or personal-data exposure
url: https://github.com/atk0309/project_ContenderOS/security/advisories/new
about: Use the private reporting flow; never disclose secrets or personal data in a public issue.
54 changes: 54 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Feature request
description: Propose a focused improvement to ContenderOS
title: "[Feature]: "
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
Explain the user problem before prescribing an implementation. Proposals must preserve
the invariants in `AGENTS.md`, especially provenance, deterministic rendering, structured
outputs, server-side secrets, and tenant isolation.

- type: checkboxes
id: preflight
attributes:
label: Before submitting
options:
- label: I searched existing issues for a similar proposal.
required: true
- label: The example contains no real CV, recruiter, account, or credential data.
required: true

- type: textarea
id: problem
attributes:
label: User problem
description: Who is affected, and what are they unable to do today?
validations:
required: true

- type: textarea
id: outcome
attributes:
label: Desired outcome
description: Describe observable behaviour, not an internal architecture.
validations:
required: true

- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: Include simpler workflows or existing features that might solve the problem.
validations:
required: true

- type: textarea
id: invariant_impact
attributes:
label: Invariant and privacy impact
description: Note any effect on provenance, export sign-off, rendering, providers, auth, or tenancy.
validations:
required: true
26 changes: 26 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## What changed

Describe the behaviour change and why it is needed. Link the issue when one exists.

## Validation

- [ ] I ran `node scripts/quality-gate.mjs --fail-on-gap` and it passed.
- [ ] I listed any intentionally skipped live-provider or Postgres checks below.
- [ ] For a non-trivial UI/render change, I verified the affected routes and states with Playwright
and checked preview/PDF parity.

Commands and results:

<!-- Include concise command evidence. Never paste secrets, tokens, real CV data, or private URLs. -->

## Safety and documentation

- [ ] This change preserves the invariants in `AGENTS.md`.
- [ ] Tests cover the changed behaviour, including deny/failure cases where relevant.
- [ ] Documentation was updated according to the doc-impact checklist, or no rule was triggered.
- [ ] Generated OpenAPI/TypeScript files are in sync when backend schemas changed.
- [ ] The diff contains no credentials, personal data, generated CVs, databases, or populated env files.

## Known risks or follow-ups

<!-- State "None" when there are no known residual risks. -->
48 changes: 48 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: codeql

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "17 4 * * 1"
workflow_dispatch:

concurrency:
group: codeql-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

jobs:
analyze:
name: CodeQL (${{ matrix.language }})
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
packages: read
security-events: write
strategy:
fail-fast: false
matrix:
language:
- javascript-typescript
- python

steps:
- uses: actions/checkout@v7

- name: Initialise CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: none
queries: security-extended

- name: Analyse
uses: github/codeql-action/analyze@v4
with:
category: /language:${{ matrix.language }}
42 changes: 42 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Code of Conduct

## Our commitment

ContenderOS is a place for constructive, technically rigorous collaboration. We welcome
contributors regardless of background, identity, experience level, or perspective, and we are
committed to keeping project spaces respectful and free from harassment.

## Expected behaviour

- Be considerate, specific, and kind when discussing people or their work.
- Critique ideas and code, not the person presenting them.
- Assume good intent while accepting correction when impact differs from intent.
- Respect privacy. Never post another person's CV, contact details, credentials, account data, or
private correspondence.
- Keep feedback relevant to the project and make room for less-experienced contributors.

## Unacceptable behaviour

- Harassment, threats, intimidation, stalking, or sustained disruption.
- Discriminatory, sexualised, insulting, or demeaning language or imagery.
- Publishing private information without explicit permission.
- Deliberate exposure of secrets, personal records, or security reports.
- Retaliation against someone who raises a good-faith concern.

## Scope

This policy applies in repository issues, pull requests, reviews, discussions, and other spaces
where someone is representing ContenderOS.

## Reporting and enforcement

Do not report sensitive conduct concerns in a public issue. Use the repository's private
**Report a vulnerability** flow and prefix the report title with `[Conduct]`; this provides a
private repository-local channel to the maintainer. If the concern involves the maintainer or you
do not want them to receive the report, use
[GitHub's abuse-reporting process](https://docs.github.com/en/site-policy/acceptable-use-policies/github-bullying-and-harassment).

Reports will be handled as confidentially as practical. Maintainers may remove content, issue a
private correction or warning, temporarily restrict participation, or permanently ban a
participant, depending on severity and pattern. Knowingly false or retaliatory reports are also a
violation; a good-faith report that cannot be substantiated is not.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ Tracked fixtures and design examples are synthetic. Keep the public repository t
## Contributing

Read [CONTRIBUTING.md](CONTRIBUTING.md) and the repository's [AGENTS.md](AGENTS.md) before changing
code. The local quality gate is required for every contribution.
code. The local quality gate is required for every contribution, and participation is governed by
the [Code of Conduct](CODE_OF_CONDUCT.md).

## License

Expand Down
1 change: 1 addition & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dev = [
"mypy>=2.3.0",
"pytest>=9.1.1",
"aiosqlite>=0.20", # offline test DB (sqlite+aiosqlite) so the suite needs no Postgres
"httpx2>=2.7.0", # Starlette 1.3 TestClient; runtime Authlib/Resend calls still use httpx
]

# Virtual project: uv never builds/installs it as a package (the Dockerfile syncs with
Expand Down
6 changes: 3 additions & 3 deletions backend/tests/test_applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from collections.abc import Iterator
from typing import Any, TypeVar

import httpx
import httpx2
import pytest
from app.ai.agents.registry import get_model_resolver, get_runner
from app.auth.deps import current_user
Expand Down Expand Up @@ -188,14 +188,14 @@ def _apply(
company: str | None = None,
jobUrl: str | None = None,
note: str | None = None,
) -> httpx.Response:
) -> httpx2.Response:
bv = _version(client, cv_id, workspace) if base_version is None else base_version
body: dict[str, object] = {"cvId": cv_id, "baseVersion": bv}
extras = (("jobTitle", jobTitle), ("company", company), ("jobUrl", jobUrl), ("note", note))
for key, val in extras:
if val is not None:
body[key] = val
res: httpx.Response = client.post(f"/workspaces/{workspace}/applications", json=body)
res: httpx2.Response = client.post(f"/workspaces/{workspace}/applications", json=body)
return res


Expand Down
6 changes: 3 additions & 3 deletions backend/tests/test_corrector.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from collections.abc import Iterator
from typing import Any, TypeVar

import httpx
import httpx2
import pytest
from app.ai.agents.registry import (
get_authoring_runner_builder,
Expand Down Expand Up @@ -213,9 +213,9 @@ def _apply(
*,
base_version: int | None = None,
workspace: str = "default",
) -> httpx.Response:
) -> httpx2.Response:
bv = _version(client, cv_id, workspace) if base_version is None else base_version
res: httpx.Response = client.post(
res: httpx2.Response = client.post(
f"/workspaces/{workspace}/cv/{cv_id}/apply",
json={"threads": threads, "baseVersion": bv},
)
Expand Down
10 changes: 5 additions & 5 deletions backend/tests/test_cv.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from collections.abc import Iterator
from typing import TypeVar

import httpx
import httpx2
import pytest
from app.ai.agents.registry import get_model_resolver, get_runner
from app.auth.deps import current_user
Expand Down Expand Up @@ -151,9 +151,9 @@ def _signoff(
*,
base_version: int | None = None,
workspace: str = "default",
) -> httpx.Response:
) -> httpx2.Response:
bv = _version(client, cv_id, workspace) if base_version is None else base_version
res: httpx.Response = client.post(
res: httpx2.Response = client.post(
f"/workspaces/{workspace}/cv/{cv_id}/signoff",
json={"bulletIds": bullet_ids, "baseVersion": bv},
)
Expand All @@ -168,9 +168,9 @@ def _edit(
*,
base_version: int | None = None,
workspace: str = "default",
) -> httpx.Response:
) -> httpx2.Response:
bv = _version(client, cv_id, workspace) if base_version is None else base_version
res: httpx.Response = client.post(
res: httpx2.Response = client.post(
f"/workspaces/{workspace}/cv/{cv_id}/edit",
json={"bulletId": bullet_id, "text": text, "baseVersion": bv},
)
Expand Down
Loading