marmalade: publication is not publicness, and a token tells you by refusing
Jeff's correction breaks published check rather than denting it. homelab-cluster publishes six documents and is private deliberately; publication.md says others, not everyone, and I read one word as the other. The tool as logged would have reported a correct repository as broken, so a superseding entry is added rather than revising the osprey entry. What survives is that bedrock's public page promising a private repository as the better answer was a real defect, and it was never about homelab-cluster. So published check must not report a verdict. It reports the identity it used, and warns when that identity is the repository's own owner — publishing is not an act you can complete alone, and a tool that verifies with your own credential has helped you complete it alone and told you it was fine. Also corrects me: I confirmed the specimen's token claim enthusiastically without testing the case that would show it wrong. A refused write names the token's scopes in the error body, so a token cannot be asked what it may do but can be told by being refused. Verified that no other channel exists — the tokens endpoint rejects token auth, and no scope header comes back on success. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris
This commit is contained in:
@@ -240,3 +240,120 @@ self-hosted gitea or gitlab may not, and **git's fallback is silent** — it war
|
|||||||
**`--depth=1` bounds the damage to one commit**, *which is why both flags are
|
**`--depth=1` bounds the damage to one commit**, *which is why both flags are
|
||||||
there and not just the filter.* **Detect the warning and say so**, rather than
|
there and not just the filter.* **Detect the warning and say so**, rather than
|
||||||
letting `list` quietly become a full clone of somebody's monorepo.
|
letting `list` quietly become a full clone of somebody's monorepo.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# The token, and `published check` was wrong
|
||||||
|
|
||||||
|
**Done with the token — delete it whenever you like.** *It is in no file, no
|
||||||
|
commit and no config; it lived in a shell variable in a scratch directory.*
|
||||||
|
|
||||||
|
## Three things it settled
|
||||||
|
|
||||||
|
**The specimen's assumption holds.** *A read token against **raw** HTTP on a
|
||||||
|
private repository:* `404` *anonymous,* **`200` with `Authorization: token`** *(and
|
||||||
|
with `Bearer` — both forms work).* **Conditional requests work authenticated:
|
||||||
|
`If-None-Match` returned `304`.** *So `add` and `check` work on private
|
||||||
|
repositories, which is the whole of `homelab-cluster`.*
|
||||||
|
|
||||||
|
**The gitea coincidence holds on private repositories too** — *`ETag`
|
||||||
|
`530c5bef…` equals the blob hash.* **Which changes nothing**, *because we do not
|
||||||
|
use it.*
|
||||||
|
|
||||||
|
**And the specimen's sharpest claim is now measured rather than asserted:**
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/repos/jeffry/homelab-cluster
|
||||||
|
permissions: {admin: true, push: true, pull: true} ← with a READ token
|
||||||
|
```
|
||||||
|
|
||||||
|
> **A token cannot be asked what it may do.** *The API reports the **account's**
|
||||||
|
> rights.* **Scope is set once at creation and invisible afterwards, so the name
|
||||||
|
> is the only record** — *and that is now a thing we have seen rather than a thing
|
||||||
|
> we were told.*
|
||||||
|
|
||||||
|
## You are right, and it breaks my design rather than dents it
|
||||||
|
|
||||||
|
**I built `published check` on "can somebody anonymous fetch this", and
|
||||||
|
publication is not the same as being public.** *`homelab-cluster` publishes six
|
||||||
|
documents and is private on purpose, and that is not a defect — **it is what
|
||||||
|
`publication.md` actually says:***
|
||||||
|
|
||||||
|
> **What a repository has handed over for **others** to depend on.**
|
||||||
|
|
||||||
|
***Others*, not *everyone*.** *I read one word as the other and built a test on
|
||||||
|
it.*
|
||||||
|
|
||||||
|
## What the check has to be instead
|
||||||
|
|
||||||
|
**The question is not "is this public". It is "can the audience I published for
|
||||||
|
fetch it".** *And the audience is not a thing the tool can know.*
|
||||||
|
|
||||||
|
**So `published check` must never report success. It reports the identity it
|
||||||
|
used:**
|
||||||
|
|
||||||
|
```
|
||||||
|
gitea.md 200 as anonymous
|
||||||
|
gitea.md 200 as reader
|
||||||
|
gitea.md 200 as jeffry — OWNER, this proves nothing
|
||||||
|
```
|
||||||
|
|
||||||
|
**The third line is the one that earns the command.** *`/api/v1/user` gives the
|
||||||
|
login; the repository gives its owner; if they match, **the check is vacuous and
|
||||||
|
should say so instead of printing something green.***
|
||||||
|
|
||||||
|
> **That is `publication.md`'s own sentence, enforced:** *publishing is not an act
|
||||||
|
> you can complete alone.* **A tool that verifies your publication using your own
|
||||||
|
> credential has helped you complete it alone**, *and told you it was fine.*
|
||||||
|
|
||||||
|
**And it ties your `auth` section to something real:** *a kubeconfig-shaped config
|
||||||
|
is not only credentials, it is **named identities you can test as**.* **`--as
|
||||||
|
<context>` is the whole feature.**
|
||||||
|
|
||||||
|
## Affirm: no audience declaration?
|
||||||
|
|
||||||
|
**I do not want to add a field where a repository states who it published for.**
|
||||||
|
|
||||||
|
*It would let the tool compare intent to result, which sounds good* — **and it
|
||||||
|
asserts a category nobody has decided**, *which is the argument that killed
|
||||||
|
`init`.* **Report the identity, let the person judge the audience.**
|
||||||
|
|
||||||
|
**Fallback if unanswered:** *no declaration; `--as` defaults to anonymous, and the
|
||||||
|
owner-identity warning is always on.*
|
||||||
|
|
||||||
|
## You were right to make me try it, and it corrects me
|
||||||
|
|
||||||
|
**I wrote, one message ago, that the specimen's claim was "now measured rather
|
||||||
|
than asserted." I had measured the wrong half.**
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/v1/repos/loom/loom-cli/contents/… 403
|
||||||
|
token does not have at least one of required scope(s),
|
||||||
|
required=[write:repository],
|
||||||
|
token scope=read:activitypub,read:admin,read:misc,read:notification,
|
||||||
|
read:organization,read:package,read:issue,read:repository,read:user
|
||||||
|
```
|
||||||
|
|
||||||
|
**The refusal names the scope.** *So "a token cannot be asked what it may do" is
|
||||||
|
too strong* — **and I confirmed it enthusiastically without testing the one case
|
||||||
|
that would have shown it wrong**, which is the failure mode this project keeps
|
||||||
|
finding in itself.
|
||||||
|
|
||||||
|
**What is actually true, and it is sharper:**
|
||||||
|
|
||||||
|
> **A token cannot be asked what it may do. It can only be told, by being
|
||||||
|
> refused.**
|
||||||
|
|
||||||
|
*Verified: `/api/v1/users/{u}/tokens` rejects token auth entirely (`401 auth
|
||||||
|
required` — it wants a password), no scope header comes back on success, and
|
||||||
|
`/api/v1/repos/…` reports `admin, push, pull: true` for a token that cannot
|
||||||
|
write.* **The only channel is the error body.**
|
||||||
|
|
||||||
|
**For us that changes the reason and not the rule.** *`loomctl` never writes, so it
|
||||||
|
will never provoke the one response that would tell it anything.* **The name
|
||||||
|
remains the only record we will ever see** — *but because we never ask, not
|
||||||
|
because nobody answers.*
|
||||||
|
|
||||||
|
**One concrete consequence:** *gitea's error bodies carry the useful part.*
|
||||||
|
**Surface them rather than mapping a `403` to a sentence of our own** — *we would
|
||||||
|
be throwing away the only scope information the host ever emits.*
|
||||||
|
|||||||
@@ -263,3 +263,62 @@ have had to already depend on that document to have pulled it** — *and the thi
|
|||||||
needed was the one I did not know I was missing.* **A fetcher does not solve
|
needed was the one I did not know I was missing.* **A fetcher does not solve
|
||||||
discovery, and this story is partly a discovery problem wearing a freshness
|
discovery, and this story is partly a discovery problem wearing a freshness
|
||||||
problem's clothes.**
|
problem's clothes.**
|
||||||
|
|
||||||
|
## 2026-09-07 — supersedes the `reachable` entry: publication is not publicness `marmalade`
|
||||||
|
|
||||||
|
**The entry above records three publication failures found by `reachable` and says
|
||||||
|
all three are fixed. One of them was not a failure.**
|
||||||
|
|
||||||
|
**`jeffry/homelab-cluster` is private on purpose** — *it describes a running
|
||||||
|
cluster, and its owner does not want outsiders reading what is on it.* **It
|
||||||
|
publishes six documents to an audience that is not the public**, *which
|
||||||
|
`publication.md` permits in the word we misread:*
|
||||||
|
|
||||||
|
> **What a repository has handed over for **others** to depend on.**
|
||||||
|
|
||||||
|
***Others*, not *everyone*.**
|
||||||
|
|
||||||
|
**So the tool as logged would have reported a correct repository as broken.** *An
|
||||||
|
anonymous fetch returning `404` is the intended outcome there*, **and a check that
|
||||||
|
treats anonymous reachability as success produces a false positive on every
|
||||||
|
deliberately-private publisher.**
|
||||||
|
|
||||||
|
**What survives:** *the defect that round found in `bedrock/starting.md` was real,
|
||||||
|
and it was never about `homelab-cluster`.* **A public document promised that a
|
||||||
|
private repository was the better answer**, *and the promise was the defect.*
|
||||||
|
**The link was removed; naming it as private, the way `.loom` names `settled`,
|
||||||
|
would also have answered it and would have kept the better document findable.**
|
||||||
|
*That call is loom's and it is already made.*
|
||||||
|
|
||||||
|
**Believed to advance:** *a check that cannot fail teaches nothing, and one that
|
||||||
|
fails on correct repositories is worse* — **it trains people to ignore it.**
|
||||||
|
|
||||||
|
**Belief that could be shown wrong:** *that anonymous is still the right default.*
|
||||||
|
**If most publication here is to private audiences, the default is wrong** and the
|
||||||
|
command should refuse to run without being told who to ask as.
|
||||||
|
|
||||||
|
## 2026-09-07 — measured: a read token, and what a host will tell you `marmalade`
|
||||||
|
|
||||||
|
**A gitea read token was issued for one session and destroyed after.** *Recorded
|
||||||
|
because these are facts about the host that nothing else here writes down.*
|
||||||
|
|
||||||
|
**A read token authenticates raw HTTP on a private repository.** *`404`
|
||||||
|
anonymously, `200` with `Authorization: token` or `Bearer`, and `If-None-Match`
|
||||||
|
returns `304` authenticated.* **So `add` and `check` work against private
|
||||||
|
repositories** — *the assumption the specimen made and nobody had run.*
|
||||||
|
|
||||||
|
**`/api/v1/repos/{o}/{r}` reports `admin, push, pull: true` for a token that
|
||||||
|
cannot write.** *Those are the account's rights.*
|
||||||
|
|
||||||
|
**But a refused write names the token's scopes in the error body.** *So:*
|
||||||
|
|
||||||
|
> **A token cannot be asked what it may do. It can only be told, by being
|
||||||
|
> refused.**
|
||||||
|
|
||||||
|
*Supersedes the specimen's "the name is the only record", which was too strong.*
|
||||||
|
**For this tool the rule is unchanged and the reason is different:** *`loomctl`
|
||||||
|
never writes, so it never provokes the only response that would tell it anything.*
|
||||||
|
|
||||||
|
**Belief that could be shown wrong:** *that gitea keeps doing this.* **The scope
|
||||||
|
list in an error body is not a documented interface** — *it is a message, and
|
||||||
|
messages change.*
|
||||||
|
|||||||
Reference in New Issue
Block a user