Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
1d55260
feat(state): parse battery clamshell setting
LMLiam Jul 28, 2026
756156a
feat(status): report battery clamshell state
LMLiam Jul 28, 2026
d9a2b54
feat(control): add verified state transitions
LMLiam Jul 28, 2026
7c5cfeb
feat(helper): restrict privileged power mutations
LMLiam Jul 28, 2026
dbf68e0
feat(cli): add clamshell control commands
LMLiam Jul 28, 2026
eb23e6f
fix(security): use protected helper location
LMLiam Jul 28, 2026
78ad84d
feat(setup): define secure helper installation
LMLiam Jul 28, 2026
e241a02
feat(setup): add helper setup and removal commands
LMLiam Jul 28, 2026
e0191c3
docs(quality): define repository standards
LMLiam Jul 28, 2026
97c3ebe
docs(quality): plan repository improvements
LMLiam Jul 28, 2026
aba0a1c
refactor(layout): organise code by responsibility
LMLiam Jul 28, 2026
5fb2321
refactor(core): separate domain responsibilities
LMLiam Jul 28, 2026
081d7c6
style(swift): adopt Google formatting
LMLiam Jul 28, 2026
dffb9b4
build(lint): enforce Swift conventions
LMLiam Jul 28, 2026
452a9a5
build(checks): add local verification entry point
LMLiam Jul 28, 2026
7d5be24
ci(checks): enforce repository quality
LMLiam Jul 28, 2026
03d2c8b
ci(release): add security and release automation
LMLiam Jul 28, 2026
16efe31
docs(community): complete repository guidance
LMLiam Jul 28, 2026
a865666
test(safety): isolate privileged command checks
LMLiam Jul 28, 2026
3c9dbb5
ci(release): restrict manual releases to main
LMLiam Jul 28, 2026
9ce4d0b
build(lint): remove inactive analyzer rule
LMLiam Jul 28, 2026
335e75a
docs(quality): align repository guidance
LMLiam Jul 28, 2026
bb62e62
fix(privilege): stage installation files before commit
LMLiam Jul 28, 2026
32636f6
fix(privilege): reject the sudoers ALL alias
LMLiam Jul 28, 2026
e73e6a9
fix(cli): make status output unconditional
LMLiam Jul 28, 2026
64d44f3
build(package): declare the CLI test dependency
LMLiam Jul 28, 2026
f134e77
ci(checks): harden workflow validation
LMLiam Jul 28, 2026
7a6d54d
ci(release): align dependency commit conventions
LMLiam Jul 28, 2026
a64063d
build(checks): separate shell assignment
LMLiam Jul 28, 2026
45a173f
docs(quality): align review implementation plan
LMLiam Jul 28, 2026
5553bf9
ci(pr): bootstrap trusted subject validation
LMLiam Jul 28, 2026
12b9067
fix(checks): close review validation gaps
LMLiam Jul 29, 2026
2c10be2
docs(review): define CodeRabbit policy
LMLiam Jul 29, 2026
74ffd8c
docs(review): plan CodeRabbit configuration
LMLiam Jul 29, 2026
153b0a9
ci(review): configure high-signal CodeRabbit reviews
LMLiam Jul 29, 2026
f5add89
ci(workflows): clarify automation steps
LMLiam Jul 29, 2026
e0ce5f4
docs(conduct): remove placeholder policy
LMLiam Jul 29, 2026
a485679
ci(codeql): resolve dependencies before tracing
LMLiam Jul 29, 2026
dda5e2c
ci(cache): reuse Swift dependencies
LMLiam Jul 29, 2026
631e264
build(lint): decouple SwiftLint tooling
LMLiam Jul 29, 2026
f08d401
docs(style): require simplified technical English
LMLiam Jul 29, 2026
cecef35
ci(codeql): prebuild external dependencies
LMLiam Jul 29, 2026
ffe3002
revert(codeql): remove ineffective dependency prebuild
LMLiam Jul 29, 2026
96b692d
fix(ci): install pinned SwiftLint binary
LMLiam Jul 29, 2026
56555c0
perf(codeql): remove pull request scan
LMLiam Jul 29, 2026
6fd7e27
docs(review): correct implementation plans
LMLiam Jul 29, 2026
30f4a62
docs(review): clarify verification execution
LMLiam Jul 29, 2026
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
111 changes: 111 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: "en-GB"
early_access: false

reviews:
profile: "assertive"
request_changes_workflow: true
high_level_summary: true
high_level_summary_in_walkthrough: true
high_level_summary_instructions: >-
Summarise user-visible behaviour, security boundaries, and verification in
concise British English. Use ASD-STE100 Simplified Technical English for
documentation. Keep required technical terms, product names, commands,
identifiers, quoted interface text, and standard names. Omit release-note
filler.
review_status: true
review_details: false
commit_status: true
fail_commit_status: false
collapse_walkthrough: true
changed_files_summary: true
sequence_diagrams: false
estimate_code_review_effort: false
assess_linked_issues: true
related_issues: false
related_prs: false
suggested_labels: false
auto_apply_labels: false
suggested_reviewers: false
in_progress_fortune: false
poem: false
enable_prompt_for_ai_agents: false
abort_on_close: true

auto_review:
enabled: true
auto_incremental_review: false
drafts: false

finishing_touches:
docstrings:
enabled: false

pre_merge_checks:
docstrings:
mode: "off"
title:
mode: "off"
description:
mode: "warning"
issue_assessment:
mode: "warning"

path_instructions:
- path: "**/*"
instructions: |
Report only findings with a concrete correctness, security, or
maintainability consequence. State the consequence and the smallest
suitable remedy. Do not request cosmetic churn, redundant comments,
or documentation for self-explanatory implementation details. Verify
each finding against the current code and repository conventions.
- path: "**/*.swift"
instructions: |
Follow the Google Swift Style Guide and the repository SwiftLint
policy. Prefer idiomatic Swift 6, narrow access control, Sendable-safe
concurrency, typed errors, and explicit failure handling. Treat one
primary responsibility per file as a design goal, not a rigid
one-declaration rule.
- path: "Sources/ClamshellCore/Privilege/**/*.swift"
instructions: |
Treat helper actions, sudoers generation, filesystem replacement,
ownership, permissions, username handling, and process construction as
security boundaries. Check exact allow-lists and failure consistency.
- path: "Sources/ClamshellHelper/**/*.swift"
instructions: |
Treat every accepted argument and privileged command as part of the
root boundary. Reject broader command shapes and require observable
verification of requested state changes.
- path: "Tests/**/*.swift"
instructions: |
Review observable behaviour, failure paths, and privilege constraints.
Tests must not mutate live power settings or privileged system files.
Do not request assertions about private implementation or call order
unless order is part of the contract.
- path: ".github/workflows/**"
instructions: |
Check immutable action pinning, least-privilege permissions, untrusted
pull-request code execution, concurrency, timeouts, and fail-closed
status handling. Request comments only for non-obvious security
constraints or necessary tool suppressions.
- path: "scripts/**"
instructions: |
Check quoting, exit-status preservation, temporary-file cleanup, and
fail-closed behaviour. Prefer portable shell accepted by ShellCheck.
- path: "**/*.md"
instructions: |
Check technical accuracy against current behaviour. Require ASD-STE100
Simplified Technical English and British English spelling. Permit
required technical terms, product names, commands, identifiers, quoted
interface text, and standard names. Reject stale paths, unsupported
claims, and internal AI process metadata.

tools:
swiftlint:
enabled: true
config_file: ".swiftlint.yml"
shellcheck:
enabled: true

chat:
auto_reply: true
19 changes: 19 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.swift]
indent_style = space
indent_size = 2
max_line_length = 100

[{*.json,*.yml,*.yaml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* text=auto eol=lf
*.icns binary
*.png binary
*.dmg binary
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @LMLiam
103 changes: 103 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Contributing

## Prerequisites

You need macOS, Xcode 26.6 or later, and Swift 6.3 or later. You also need
SwiftLint 0.65.0 and [actionlint](https://github.com/rhysd/actionlint).
Install the development tools with:

```bash
brew install actionlint swiftlint
```

The future companion app also requires
[XcodeGen](https://github.com/yonaskolb/XcodeGen).

## Setup

Fork the repository, clone your fork, and create a branch from `main`. Resolve
the package dependencies once after cloning:

```bash
swift package resolve
```

Do not run tests against live privileged paths. Tests must use fake process and
filesystem boundaries; they must never change `pmset`, invoke `sudo`, or write
to `/Library/PrivilegedHelperTools` or `/etc/sudoers.d`.

## Checks

Run the complete local gate before each pull request:

```bash
scripts/check.sh
```

The script checks formatting, SwiftLint, tests, debug and release builds, and
GitHub Actions workflows. When native app targets exist, it also generates and
builds the Xcode project without code signing.

## Swift style

Follow the [Google Swift Style Guide](https://google.github.io/swift/).
`swift-format` owns formatting; SwiftLint owns semantic and maintainability
rules. Prefer self-describing names. Add comments only for contracts,
constraints, or decisions that the code does not make clear.

Keep one primary responsibility per file. A private helper may remain beside
its sole consumer. Do not create generic `Utils`, `Common`, or `Models`
directories.

Fix lint findings in code where practical. A SwiftLint suppression must have a
narrow scope and an adjacent explanation of why the rule does not apply.

## Documentation style

Use ASD-STE100 Simplified Technical English for all documentation. Use British
English spelling. Use short sentences and active voice. Give one instruction
in each sentence. Use one term for each item or action.

You can use an unapproved term when technical accuracy requires it. Examples
include product names, commands, code identifiers, API names, quoted interface
text, and standard names. Do not replace a precise technical term with an
ambiguous word.

## Commits

Every commit and pull-request title must use:

```text
verb(area): description
```

Examples include `feat(status): report battery state` and
`fix(setup): preserve an existing sudoers policy`. The accepted verbs are
`feat`, `fix`, `docs`, `test`, `build`, `ci`, `refactor`, `perf`, `style`,
`chore`, and `revert`.

Dependency updates use `build(deps): ...` so they remain within the accepted
commit vocabulary and are hidden from the public changelog.

## Tests

Test observable behaviour through public or internal boundaries. Cover failure
paths and privilege constraints. Avoid assertions about private implementation
details, mock call order unless order is part of the contract, and live system
mutation.

## Pull requests

Keep each pull request focused and link the issue it addresses. Describe any
change to command output, exit status, system paths, permissions, sudoers
policy, or the helper allow-list. Include the commands you ran and update user
documentation when behaviour changes.

Maintainer approval and all required checks are needed before merge. The
repository uses squash merging, so the pull-request title becomes the release
commit subject.

## Security

Do not report vulnerabilities in a public issue. Follow the private reporting
instructions in [SECURITY.md](SECURITY.md).
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/LMLiam/clamshellctl/security/advisories/new
about: Send vulnerability details privately to the maintainer.
- name: Support and usage questions
url: https://github.com/LMLiam/clamshellctl/issues/new?template=question.yml
about: Ask about macOS, Homebrew, or clamshellctl usage.
50 changes: 50 additions & 0 deletions .github/ISSUE_TEMPLATE/question.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Support question
description: Ask about macOS, Homebrew, or clamshellctl usage.
title: "question(area): "
labels:
- question
body:
- type: markdown
attributes:
value: |
Do not include passwords, tokens, private keys, complete environment
dumps, or unrelated personal information.
- type: textarea
id: question
attributes:
label: Question
description: Explain what you are trying to do and where you are stuck.
validations:
required: true
- type: input
id: macos-version
attributes:
label: macOS version
placeholder: "26.6"
validations:
required: true
- type: dropdown
id: installation
attributes:
label: Installation method
options:
- Homebrew
- Companion-app DMG
- Source checkout
- Not installed
validations:
required: true
- type: textarea
id: diagnostics
attributes:
label: Safe diagnostic output
description: Include concise command output when it helps explain the question.
validations:
required: false
- type: checkboxes
id: safety
attributes:
label: Safety check
options:
- label: I removed passwords, tokens, private keys, and unrelated personal data.
required: true
28 changes: 28 additions & 0 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Security policy

## Supported versions

Only the latest published release receives security fixes. The project has not
published its first release yet.

## Report a vulnerability

Use [GitHub private vulnerability reporting](https://github.com/LMLiam/clamshellctl/security/advisories/new).
Do not open a public issue for a suspected vulnerability.

Include the affected version, macOS version, impact, reproduction steps, and a
minimal proof when safe. Do not include live credentials, secrets, personal
data, or destructive commands. We will acknowledge a report within seven days
and keep you informed while we validate and fix it.

## Security-sensitive surfaces

Changes to the root-owned helper, sudoers policy, installation paths, ownership
or permissions, process execution, and unsigned app distribution require extra
review. The helper must continue to accept only the exact `enable` and
`disable` actions. The sudoers policy must not grant password-free access to
the public CLI, `pmset`, a shell, or a user-writable executable.

The planned companion app and DMG will use ad-hoc signing without Apple
notarisation. Release documentation must state that boundary and provide the
specific Gatekeeper approval steps without implying Apple review.
14 changes: 14 additions & 0 deletions .github/SUPPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Support

- Report reproducible defects with the [bug form](https://github.com/LMLiam/clamshellctl/issues/new?template=bug.yml).
- Propose a change with the [feature form](https://github.com/LMLiam/clamshellctl/issues/new?template=feature.yml).
- Report vulnerabilities through [private vulnerability reporting](https://github.com/LMLiam/clamshellctl/security/advisories/new).
- Ask macOS, Homebrew, or usage questions with the [support form](https://github.com/LMLiam/clamshellctl/issues/new?template=question.yml).

This is a community project. Opening an issue does not guarantee individual
support or a response time.

Safe diagnostics include `clamshellctl --version` and `clamshellctl status`.
Review output before posting it. Do not publish sudoers contents when they
contain unexpected local changes; use private vulnerability reporting if those
changes may expose a security problem.
27 changes: 27 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: 2
updates:
- package-ecosystem: swift
directory: /
schedule:
interval: weekly
day: monday
time: "06:00"
timezone: Europe/London
open-pull-requests-limit: 5
groups:
swift-development:
patterns:
- "*"

- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
day: monday
time: "06:00"
timezone: Europe/London
open-pull-requests-limit: 5
groups:
actions:
patterns:
- "*"
Loading