mirror of
https://github.com/forkless/NotAlterra.git
synced 2026-08-23 19:12:37 +02:00
move policy docs to docs/ for cleaner root
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# Security Audit
|
||||
|
||||
**Project:** NotAlterra (Subnautica 2 save-file manager)
|
||||
**Date:** 2026-06-01
|
||||
**Scope:** Full source code — `src/`, `examples/`, build pipeline
|
||||
|
||||
## Summary
|
||||
|
||||
No malicious or exploitable behavior detected. NotAlterra is an offline
|
||||
terminal application with no network access, no unsafe code, and
|
||||
no data exfiltration surface.
|
||||
|
||||
## Audit Results
|
||||
|
||||
| Category | Finding |
|
||||
|---|---|
|
||||
| `unsafe` blocks | None |
|
||||
| Network (sockets, HTTP, TLS) | None — zero network dependencies |
|
||||
| Process spawning | `guard.rs` (tasklist / pgrep) — dormant, not called |
|
||||
| Dynamic loading | None |
|
||||
| `include_bytes!` / obfuscation | None |
|
||||
| Thread spawning | Whale animation only — benign |
|
||||
|
||||
## Process Guard
|
||||
|
||||
`guard.rs` contains code to detect a running Subnautica 2 instance via
|
||||
`tasklist` (Windows) and `pgrep` (Linux). This code is **dormant** —
|
||||
`check_game_not_running()` is never called from `main.rs`.
|
||||
|
||||
The intent is to prevent accidental save corruption by warning the user
|
||||
if the game is running during backup or recovery operations.
|
||||
This feature may be re-introduced in a future release provided it does not trigger false positives or interfere with normal system operation.
|
||||
|
||||
## File I/O
|
||||
|
||||
All file writes are confined to declared paths:
|
||||
|
||||
- `config.ini` — save-path cache, scan timestamp, disclaimer flag
|
||||
- `NotAlterra_Backups/` — backup archives
|
||||
- `transaction.log` — timestamped action log
|
||||
|
||||
No writes outside these directories. No reads beyond the Subnautica 2
|
||||
Saved folder tree.
|
||||
|
||||
## Dependencies
|
||||
|
||||
No dependency introduces network access or code execution risks. Full
|
||||
dependency tree is pinned via `Cargo.lock`.
|
||||
|
||||
## Conclusion
|
||||
|
||||
NotAlterra is safe to use. It operates entirely within the user's
|
||||
local filesystem and performs only the save-management operations it
|
||||
declares.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Code Signing Policy
|
||||
|
||||
NotAlterra uses automated, auditable pipelines to ensure every release
|
||||
artifact is traceable to its source.
|
||||
|
||||
## Build & Signing Process
|
||||
|
||||
All release binaries are built from this repository by GitHub Actions on
|
||||
tag push. The CI workflow runs on `ubuntu-latest`, installs the
|
||||
required toolchain via `dtolnay/rust-toolchain@stable`, and produces
|
||||
deterministic artifacts using a locked `Cargo.lock` and pinned
|
||||
dependency versions.
|
||||
|
||||
## AI Usage Disclosure
|
||||
|
||||
This project uses agentic AI coding tools (e.g., DeepSeek TUI,
|
||||
GitHub Copilot) as assistive aides for code generation and review. AI
|
||||
tools operate under human supervision only:
|
||||
|
||||
- Every code change is reviewed and committed by a human maintainer.
|
||||
- AI-generated code is identified in commit history — no attempt is made
|
||||
to obscure or anonymize the source.
|
||||
- All contributions pass the same lint and verification gates as any
|
||||
human-authored change.
|
||||
|
||||
## Integrity
|
||||
|
||||
AI tools do not have direct write access to the release pipeline or the
|
||||
repository's tag namespace. Builds are triggered exclusively by signed
|
||||
Git tags, which can only be created by a human maintainer with access to
|
||||
the project's GPG key.
|
||||
|
||||
## Privacy
|
||||
|
||||
NotAlterra does not collect, transmit, or store any personal user data.
|
||||
The application runs entirely offline:
|
||||
|
||||
- No telemetry, no analytics, no crash reporters.
|
||||
- No network requests — the binary never opens a socket.
|
||||
- All configuration is stored locally in `config.ini` alongside the
|
||||
executable.
|
||||
|
||||
The only potentially identifying information stored is the game's
|
||||
save-folder path in `config.ini`, which includes the current Windows
|
||||
username. This path never leaves the local machine — it is read once on
|
||||
startup and used exclusively to locate saves and configuration files.
|
||||
|
||||
Because no data is collected or transmitted, there is nothing to share,
|
||||
sell, or expose. This section serves as a safe-harbor statement:
|
||||
NotAlterra is designed to respect user privacy by collecting nothing at
|
||||
all.
|
||||
|
||||
## Signing
|
||||
> **Status: pending certification.** No binaries have been signed by
|
||||
> SignPath yet. This policy exists for transparency and privacy
|
||||
> documentation while the project prepares for certification.
|
||||
|
||||
Only binaries produced by the official CI runner from the `master`
|
||||
branch will be submitted to SignPath for signing. Manual or off-CI
|
||||
builds are never shipped as signed releases.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Design Decisions
|
||||
|
||||
This file captures the rationale behind significant architecture and format
|
||||
choices, so the reasoning is preserved for future maintainers (including
|
||||
yourself six months from now).
|
||||
|
||||
---
|
||||
|
||||
## Sentinel File vs config.ini (v0.3.2)
|
||||
|
||||
### Problem
|
||||
`config.ini` persisted the save folder path to disk, including the user's
|
||||
filesystem-username. This is a privacy concern — paths are visible next to
|
||||
the binary.
|
||||
|
||||
### Decision
|
||||
Remove `config.ini` entirely. The save folder is session-only — set it each
|
||||
time via **Set save folder**. The disclaimer acceptance is tracked via a
|
||||
0-byte sentinel file (`NotAlterra_LICENSE_ACCEPTED`) alongside the binary.
|
||||
|
||||
### Rationale
|
||||
|
||||
**Privacy** — no paths written to disk. The save folder exists only in
|
||||
memory while the tool runs.
|
||||
|
||||
**Simplicity** — no config parsing, no INI format to maintain, no migration
|
||||
code for renamed keys.
|
||||
|
||||
**Sentinel, not config** — a 0-byte file communicates exactly one boolean
|
||||
(disclaimer accepted). It cannot grow into a configuration file over time.
|
||||
The format intentionally prevents scope creep.
|
||||
|
||||
**What was removed:**
|
||||
- `AppConfig` struct (save_path, ini_path, save_scan, disclaimer_accepted)
|
||||
- `load_config()` / `save_config()` with INI parsing
|
||||
- Cached `ini_path` — now derived from save folder at runtime
|
||||
- Four integration tests for config round-trips
|
||||
|
||||
---
|
||||
|
||||
## Manual Path Entry vs Auto-Discovery (v0.3.0)
|
||||
|
||||
### Problem
|
||||
Auto-discovery scanned user profiles and system directories for Subnautica 2
|
||||
save folders. This is a privacy concern — it traverses `/home/*` (Linux) and
|
||||
`C:\Users\*` (Windows).
|
||||
|
||||
### Decision
|
||||
Replace full auto-discovery with manual path entry via **Set save folder**.
|
||||
Keep a lightweight `quick_discover()` that checks only the current user's
|
||||
default install paths at startup.
|
||||
|
||||
### Rationale
|
||||
|
||||
**Privacy** — no scanning of other users' profiles or system drives.
|
||||
|
||||
**Current-user convenience** — `quick_discover()` checks 1 path on Windows,
|
||||
3 paths on Linux, all within the current user's own directories. Returns
|
||||
the first match silently, no UI. If nothing is found, the user enters their
|
||||
path manually.
|
||||
|
||||
**Discovery module retained** — `validate_custom_path()` and
|
||||
`derive_ini_path()` still live in `discovery.rs` for the manual entry flow.
|
||||
The aggressive scan functions (`discover_save_folders()`, `scan_other_users()`,
|
||||
`walk_for_subnautica()`) are removed.
|
||||
|
||||
---
|
||||
|
||||
## tar.gz Backup Format (v0.4.0)
|
||||
|
||||
### Problem
|
||||
Directory-tree backups (`NotAlterra_Backups/notalterra_copy_<timestamp>/`)
|
||||
are messy, uncompressed, and have no integrity guarantees.
|
||||
|
||||
### Decision
|
||||
One `tar.gz` archive per backup event, stored in `backups/saves/`.
|
||||
|
||||
### Rationale
|
||||
|
||||
**No vendor lock-in** — standard `tar -xzf` recovers data without the tool.
|
||||
If NotAlterra stops working, the user's backups are still accessible with
|
||||
standard system utilities.
|
||||
|
||||
**Single file per event** — reduces clutter. One backup = one file, not
|
||||
a directory tree with 15+ loose save files.
|
||||
|
||||
**Compression** — save files compress well (~75MB → ~20MB). Reduces disk
|
||||
usage without user effort.
|
||||
|
||||
**Pure Rust implementation** — `tar` + `flate2` crates, 200M+ downloads
|
||||
combined. No system dependencies, no external tools.
|
||||
|
||||
**Per-entry restore** — extracting a single save file from the archive
|
||||
does not require decompressing the entire archive.
|
||||
|
||||
### Safeguards
|
||||
|
||||
- **Atomic write**: backup written to `.tmp` file, then atomically renamed.
|
||||
Power loss during backup discards a temp file, not a real backup.
|
||||
- **Integrity check after creation**: archive is read back and validated
|
||||
before reporting success.
|
||||
- **SHA256 manifest**: a `MANIFEST` file inside each archive records the
|
||||
hash of every contained save file. On restore, each extracted file is
|
||||
verified against its expected hash — silent bit-rot detected before bad
|
||||
data reaches the save folder.
|
||||
- **Fuzz target**: round-trip fuzzing (create archive from diverse inputs →
|
||||
restore → compare) catches logic bugs.
|
||||
|
||||
### Migration
|
||||
Existing `NotAlterra_Backups/` directory-tree backups are detected and
|
||||
transparently imported on first run after upgrade. No manual migration
|
||||
required.
|
||||
@@ -0,0 +1,113 @@
|
||||
# Governance
|
||||
|
||||
NotAlterra is maintained by a single developer. This document describes how
|
||||
decisions are made, how access is controlled, and what happens if the
|
||||
maintainer becomes unavailable.
|
||||
|
||||
## Decision Making
|
||||
|
||||
| Area | Process |
|
||||
|---|---|
|
||||
| Feature scope | Maintainer decides. Community input via issues and discussions is encouraged but non-binding. |
|
||||
| Code review | All changes pass through CI (`cargo check`, `cargo test`, `cargo doc`). Human review is performed by the maintainer before signing. |
|
||||
| Release | Signed GPG tag by the maintainer. No automated tag creation. CI builds, packages, and attaches provenance. |
|
||||
| Policy documents | Maintainer drafts. Significant changes are committed with justification in the commit message. |
|
||||
| Security issues | Reported via email. Patched within 48 hours. Disclosed publicly after patch release. |
|
||||
|
||||
## Maintainer
|
||||
|
||||
- **GitHub**: [forkless](https://github.com/forkless)
|
||||
- **Contact**: forkless@protonmail.com
|
||||
- **GPG key**: [314BB48A3C72D8EC2830B8BED2B0DF63E2CBEA16](https://github.com/forkless.gpg)
|
||||
|
||||
## Bus Factor
|
||||
|
||||
NotAlterra has a bus factor of one — only the maintainer holds the GPG key
|
||||
and push access to the repository.
|
||||
|
||||
### Proposed Mitigation
|
||||
|
||||
An emergency signing key stored on a USB stick in a sealed envelope, held
|
||||
by a non-technical trusted person. The envelope also contains the passphrase.
|
||||
The key is independent from the maintainer's daily key and revocable if
|
||||
compromised.
|
||||
|
||||
The envelope is to be opened only if the maintainer is unreachable for 90+
|
||||
consecutive days with no public activity. A technical contact would be
|
||||
designated to sign releases using the emergency key.
|
||||
|
||||
*This mitigation is not yet in place — documented here as intent.*
|
||||
|
||||
### Access Recovery Plan
|
||||
|
||||
If the maintainer becomes unavailable for an extended period (unreachable
|
||||
for 90+ days with no public activity), the following steps are available to
|
||||
the community:
|
||||
|
||||
1. **Fork the repository.** All code, documentation, and build scripts are
|
||||
publicly available under the MIT license. The project can be continued
|
||||
under new maintainership.
|
||||
|
||||
2. **Contact GitHub Support.** Repository transfer can be requested through
|
||||
GitHub's deceased user policy or owner unreachability process.
|
||||
|
||||
3. **Replace the GPG key.** The signing key belongs to the maintainer and
|
||||
cannot be transferred. A new maintainer should generate a new key, add
|
||||
it to the CI secrets, and update this document.
|
||||
|
||||
4. **Re-establish provenance.** SLSA provenance will need to be regenerated
|
||||
under the new maintainer's identity. Historical provenance for prior
|
||||
releases remains valid.
|
||||
|
||||
### What the Maintainer Periodically Verifies
|
||||
|
||||
- GPG key expiration (checked quarterly).
|
||||
- CI pipeline is functional (every commit push triggers it).
|
||||
- Backup of repository and signing subkey exists in offline storage.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Be respectful. Be constructive. Assume good intent.
|
||||
|
||||
This project is maintained by someone learning as they go. Questions are
|
||||
welcome. Patience is appreciated. Kindness is non-negotiable.
|
||||
|
||||
## Release Checklist
|
||||
|
||||
CI now creates releases as drafts — binaries are built and uploaded but
|
||||
not published. The maintainer tests the draft binaries before publishing.
|
||||
|
||||
Before signing a release tag, the maintainer verifies:
|
||||
|
||||
- [ ] Impact analysis completed — all call sites for new/changed functions identified and updated
|
||||
- [ ] `cargo test --workspace` — all tests pass (including new integration tests for features shipped in this release)
|
||||
- [ ] `python3 tests/_check.py` — 100% doc coverage
|
||||
- [ ] CHANGELOG.md has an entry for the new version
|
||||
- [ ] `git status` — no uncommitted changes
|
||||
- [ ] `_release.md` is updated for the new version
|
||||
|
||||
After the CI run completes:
|
||||
|
||||
- [ ] Download draft binaries from the GitHub releases page
|
||||
- [ ] Test on target platform(s) — basic menu flow, backup, restore, inspect
|
||||
- [ ] Click **Publish release** on GitHub when satisfied
|
||||
|
||||
## Roadmap
|
||||
|
||||
Planned changes for upcoming releases, ordered by priority.
|
||||
|
||||
| Target | Item |
|
||||
|--------|------|
|
||||
| v0.4.0 | ✅ All v0.4.0 items completed — released 2026-06-03 |
|
||||
| v0.5.0 | CLI flags: `--backup`, `--extract <archive>`, `--inspect <savefile>` (`.sav`/`.bak`), `--list` |
|
||||
| v0.5.0 | Add migration notification dialog on startup (user sees old backups converted, old files untouched) |
|
||||
| v0.5.0 | Move existing `transaction.log` into `logs/` directory on first launch |
|
||||
|
||||
Items may shift between releases depending on feedback and urgency.
|
||||
|
||||
## Changes to This Document
|
||||
|
||||
This document is versioned with the repository. Proposed changes should be
|
||||
filed as pull requests. The maintainer has final approval.
|
||||
|
||||
Last updated: 2026-06-02.
|
||||
@@ -0,0 +1,8 @@
|
||||
# Known Issues
|
||||
|
||||
## Stale config.ini from prior versions
|
||||
|
||||
Users upgrading from v0.3.0 or earlier will have a `config.ini` file next to
|
||||
the binary that no longer serves any function. It can be safely deleted.
|
||||
|
||||
**Planned**: Auto-remove stale `config.ini` on first launch after upgrade.
|
||||
Reference in New Issue
Block a user