mirror of
https://github.com/Twigpine/node.git
synced 2026-11-12 19:13:02 -10:00
bug_fix_2
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e2ae21795a |
chore: rebrand user-facing gitlawb references to Twigpine (#520)
* chore: rebrand user-facing gitlawb references to Twigpine
Rename the product name in docs, README, CLI help/output, MCP tool
descriptions, macOS app strings, installers, npm metadata and license
headers from gitlawb/Gitlawb to Twigpine. Point GitHub links at the
renamed Twigpine org (and fix the release workflow's repository guard,
which still matched Gitlawb/node), and switch the public node hosts and
website/install URLs to twigpine.com.
Protocol and operator identifiers are intentionally unchanged
(did:gitlawb, gitlawb://, signing domains, GITLAWB_* env vars, crate
and binary names, X-Gitlawb-* headers, icaptcha and peer-network URLs);
they need a follow-up migration.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* docs: point image pulls at ghcr.io/twigpine/node and fix macOS DMG name
The release workflow publishes the container image to
ghcr.io/${GITHUB_REPOSITORY,,}, which is ghcr.io/twigpine/node since the
org rename; the old ghcr.io/gitlawb/node path no longer resolves for
anonymous pulls. Point the RUN-A-NODE docker run example, the OSS
readiness audit's claim about it, and the macOS app's generated compose
file at the published path.
The README listed the macOS DMG as "Twigpine Node.dmg", but
build-macos-app.sh writes GitlawbNode-macOS.dmg (kept on purpose), so
document the real file name.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fix(infra): keep the AWS security group description to avoid replacement
`description` on aws_security_group is ForceNew, so renaming it forced a
replace of the in-use group on the next apply of an existing deployment.
Restore the original text and note why it must stay until a separate
infra migration.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fix(macos): regenerate the app's compose file instead of treating it as a repo's
Config.repoPath fell back to the data directory when no repo clone was
found, and DockerCompose then picked up the compose file it had generated
there as if it belonged to a repo. The generator therefore only ran on
first launch, so upgraded installs kept their original compose, including
the old ghcr.io/gitlawb/node image, which no longer serves anonymous pulls.
repoPath now returns nil when there is no clone, and the app regenerates
its compose file whenever no repo compose is in use. Project directory and
named volumes are unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fix(infra): default the AWS node image to ghcr.io/twigpine/node
release.yml publishes to ghcr.io/${GITHUB_REPOSITORY,,}, which is now
ghcr.io/twigpine/node; ghcr.io/gitlawb/node denies anonymous pulls, so the
default made new deployments fail to start and the upgrade command fail
on existing ones. On an existing deployment `terraform apply` only updates
the upgrade SSM document in place (user_data drift is ignored); the new
image is pulled on the next upgrade_command.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fix(macos): keep operator edits to the generated compose, migrate only the image
|
||
|
|
de4d932609 |
docs(infra,macos): make the opt-out reachable and stop the AWS guide contradicting itself
All four are in the deployment half added last round; none is in the Rust. The AWS guide told operators two different things -------------------------------------------------- "Changing configuration" still said editing `image_tag` does not affect a running instance and routed to `-replace`, while the upgrade section thirty lines above now reinstalls the rendered compose, which carries `image_tag`. The same paragraph told operators to edit `.env` and restart — which the new "Why the upgrade rewrites the compose file" section explains is silently ineffective for any key the installed compose does not already name. Split by which file carries the change rather than deleted, because the distinction is real: values rendered into `compose.yaml` (`image_tag`, ports, `domain_name`, `db_host`, `icaptcha_*`) roll out with `apply` + `upgrade_command`; values user-data writes into `.env` at first boot (`public_url`, `bootstrap_peers`, integrations) do not propagate from tfvars at all and need an edit on the instance or a replacement. The third case is the one that bites: a setting the installed compose does not yet name is read from `.env` and dropped, so it needs the upgrade first. `--remove-orphans` stopped being inert --------------------------------------- The flag is not new, but until the upgrade rewrote `compose.yaml` it reconciled against the instance's own file, so the only orphans were hand-started containers. It now reconciles against a fresh rendering whose service set is conditional — `postgres` only when `db_host` is empty, `caddy` only when `domain_name` is set. Setting `use_rds` or clearing `domain_name` and then running what the README calls a pull-and-restart stops and removes the local postgres or the TLS terminator. That is what those variables mean, but it happens on the upgrade rather than on apply, so it is now stated next to the Terraform-owned warning. Data survives either way; both bind-mount under /mnt/data. The macOS setting had no writer -------------------------------- `enforceOwnerPush` was persisted, loaded, emitted into `.env`, and forwarded by the generated compose — and nothing set it. `SettingsWindow` had no state and no assignment, so the only way to reach the opt-out on that launch path was hand editing config.json in Application Support, which no document mentions. Editing `.env` does not work there either: `writeEnvFile()` rebuilds it from `Config` on every start. It now has a Toggle beside "Sync repos from peers", following the pattern already in that view. Three lines the change made untrue ----------------------------------- The handler test asserted "with no configuration at all" while setting `enforce_owner_push` explicitly — the right thing for the test, the wrong claim for the message. The cross-tenant docstring still described three distinct pusher DIDs after A and B were given `n1`'s owner. And OSS-READINESS-AUDIT listed unprotected branches not enforcing owner checks as a live blocker; owner checks now cover every branch, and only the UCAN half of that sentence still stands. Also dropped the `#[allow(dead_code)]` on `test_state_with`, redundant since the same commit added its call site. |
||
|
|
1f0d9ff368 |
fix(node,infra,macos): make the owner-push opt-out reach every launch path
The previous round forwarded GITLAWB_ENFORCE_OWNER_PUSH in three compose templates. Two of those are not the file their runtime actually reads, so the documented rolling-upgrade opt-out did not work where it mattered. Existing AWS instances could not opt out ----------------------------------------- `aws_instance` ignores user_data drift, so an instance keeps the compose file it was created with, and the published SSM upgrade only ran `docker compose pull && up -d`. Compose passes only the variables named in a service's `environment:` block, so a key added to the template never reached a running instance: an operator following our own instructions wrote GITLAWB_ENFORCE_OWNER_PUSH=false to /opt/gitlawb/.env, upgraded, and got the new default anyway — silently, with their CI pushers refused. The upgrade document now reinstalls the rendered compose file before restarting. It is idempotent (identical bytes on an already-current instance) and it makes the upgrade a migration rather than a restart. compose.yaml is Terraform-owned and overwritten; per-instance settings belong in .env, which is untouched. infra/aws/README.md documents that `terraform apply` must precede the upgrade, since the SSM document embeds the rendering. The packaged macOS app read a different compose file ----------------------------------------------------- The bundled Resources/docker-compose.yml is not what a packaged app runs: with no source checkout selected, `generateComposeFile()` writes its own template, whose environment block did not carry the key. `Config.writeEnvFile()` also regenerates .env on every start, so a hand-added value was discarded. Between them, a packaged-app user had no way to opt out at all. `enforceOwnerPush` is now a persisted app setting, emitted into .env on every start, and `generateComposeFile()` forwards it with the same interpolation as the bundled resource — one definition, three consistent sites. A test inherited the environment it was supposed to assert about ----------------------------------------------------------------- `default_config_refuses_a_non_owner_push` built state through `test_state`, which parses `Config` from the process environment — 47 fields come from GITLAWB_* variables. On a host exporting GITLAWB_ENFORCE_OWNER_PUSH=false, which is exactly what the rolling-upgrade guidance tells operators to set, it constructed a disabled state, let the push through to git, and failed for a reason unrelated to the code under test. Renamed to `enforced_owner_push_refuses_a_signed_non_owner` and given an explicit config through a new `test_state_with`, so it states the configuration it is about. Verified by running it both with and without the variable exported. The shipped default keeps its own env-independent proof off the parser declaration, in config::tests — a parser question and an authorization question should not share a failure mode. `test_state` now carries a warning about the hazard, since any of those 47 fields can skew a test the same way. |
||
|
|
2f0174cc04 |
fix(node): close review findings on the owner-push default
Every item below was verified against the code before changing it; two of them
were confirmed by running the probe the reviewer described.
A test the fixture sweep missed, and that could not fail
--------------------------------------------------------
`f1_write_cap_is_inert_without_a_resolvable_source_key` seeded `z6f1none` and
pushed as `z6MkF1NoKeyPusher…`, so the owner gate rejected it before it reached
the per-caller cap the test exists to measure. Its assertion was
`!matches!(r, Err(Overloaded(_)))`, which a `Forbidden` satisfies, so it reported
ok while measuring nothing — and it is not `#[cfg(unix)]`, so it did that inside
every green run. Confirmed by inverting the assertion to expect `Forbidden`: it
passed, proving the request stopped at the gate.
The pusher is now the owner, and the assertion is positive: reaching git on the
missing on-disk repo (`Err(Git(_))`) is proof the request cleared both the gate
and the cap. The sibling `f1_write_cap_key_is_per_source_not_per_repo` carried
the same weak negative in its second assertion and is tightened the same way.
The default was barely tested, and what tested it read the environment
---------------------------------------------------------------------
`Config::parse_from` consults the process environment, so on a host exporting
`GITLAWB_ENFORCE_OWNER_PUSH=false` the old `enforce_owner_push_defaults_to_true`
reported the operator's setting rather than what this crate declares — it failed
outright, which would also break any contributor who sets the variable. It is
replaced by two tests that are env-independent and behavioural:
* `enforce_owner_push_is_declared_true_independent_of_the_environment` reads
the declared default off `Config::command()`.
* `default_config_refuses_a_non_owner_push` drives the handler on an untouched
`test_state` config and asserts 403 — authenticated by a real RFC 9421
signature, so 403 rather than 401 is what makes it a statement about
authorization.
Both were checked by reverting `default_value_t` to `false`: the handler test
reports 500 where it wants 403, and the declared test reports `["false"]`.
The cross-tenant test lost its second tenant
--------------------------------------------
The sweep collapsed `u1_parked_push_does_not_shed_another_pusher_behind_the_same
_ip` onto one identity, leaving the test named for cross-tenant behaviour with a
single tenant and two docstrings describing a scenario it no longer ran. `n2` is
now owned by `z6u1nat2` and its push signs as that owner, so two distinct tenants
share one edge IP again — which is the property under test, since the per-source
key is the resolved peer address and never the DID.
Four comments outlived their premise
-------------------------------------
`repos.rs` (3 sites) and `.env.example` still said owner enforcement defaults
off. The IP-keying rationale they support is unchanged and still correct — a DID
farm defeats a DID key — so only the dead premise is rewritten: the cap is
load-bearing because the rate limiter bounds arrival rate rather than occupancy,
because the gate can be turned off for a rolling upgrade, and because one owner
can open many concurrent pushes to their own repo.
Operators on the container path got none of this
-------------------------------------------------
`GITLAWB_ENFORCE_OWNER_PUSH` is now forwarded in `docker-compose.yml`, the macOS
app's bundled compose, and `infra/aws/compose.yaml.tftpl`, defaulting to `true`
to match the node. Without it the rolling-upgrade opt-out this PR documents in
three places was unreachable for anyone running compose.
A cutover this project never promised
--------------------------------------
The README paragraph announcing a 15 September 2026 flip of
`GITLAWB_REQUIRE_SIGNED_PEER_WRITES` is removed. That flag is not changed here,
the date appears nowhere on main, and a PR about a different flag is not where
that commitment would be made. The table row for `GITLAWB_ENFORCE_OWNER_PUSH`
carries the part that belongs.
A docstring that credited the wrong thing
------------------------------------------
The field and test docs claimed the value-taking action is what makes
`GITLAWB_ENFORCE_OWNER_PUSH=false` resolve to `false`. It is not: the env form
resolved under the presence-only declaration too. What the change buys is
`--enforce-owner-push false` parsing at all, rather than erroring as an
unexpected argument. Both docstrings now say so.
|
||
|
|
d09c23da86 |
feat: macOS menu bar app for managing gitlawb-node Docker Compose stack (#8)
- Menu bar icon with colored status dot (green/yellow/red) - Start/Stop node via Docker Compose - Settings UI: ports, public URL, postgres password, auto-sync, operator config - View Logs window with live docker compose logs - Auto-start on launch and login (SMAppService) - Docker detection with install prompt - Repo root detection via compile-time path for local builds - Port variables wired through docker-compose.yml for custom port support - GITLAWB_AUTO_SYNC passthrough for peer replication toggle - Build script: scripts/build-macos-app.sh (codesign + DMG) Co-authored-by: Rimas Mocevicius <[email protected]> |