chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
A runner that logs in as the owner opens the secrets sealed to it
crates/knotless-serve/src/secrets.rs+4−2
| @@ -118,9 +118,11 @@ pub async fn list( | ||
.secrets(&p.owner, &p.repo) | ||
.map_err(anyhow::Error::from) | ||
.map_err(AppError::internal)?; | ||
// Its owner sees every one, and no value; a runner, only its own. | ||
// Its owner sees every one, and no value but those sealed to it, as a | ||
// runner that logs in as its owner; a runner, only its own. | ||
if me == p.owner { | ||
secrets.iter_mut().for_each(|s| s.sealed = None); | ||
let others = secrets.iter_mut().filter(|s| s.runner != me); | ||
others.for_each(|s| s.sealed = None); | ||
} else { | ||
secrets.retain(|s| s.runner == me); | ||
} | ||
crates/knotless-serve/tests/forge.rs+19−0
| @@ -2404,6 +2404,25 @@ fn secrets_reach_only_their_runner() { | ||
assert_eq!(sealed, [b"deploy".to_vec(), b"sealed".to_vec()]); | ||
assert_eq!(own[1].key, "did:key:zDnaeTest"); | ||
assert!(list(&x, &theirs, &od).is_empty()); | ||
// A runner that logs in as the owner sees the values sealed to it, and | ||
// still no other. | ||
put(secret("SELF", &od, &[], b"self")); | ||
let all = list(&o, &mine, &od); | ||
let values: Vec<_> = all | ||
.iter() | ||
.map(|s| (s.name.as_str(), s.sealed.clone())) | ||
.collect(); | ||
assert_eq!( | ||
values, | ||
[ | ||
("DEPLOY", None), | ||
("SELF", Some(b"self".to_vec())), | ||
("TOKEN", None), | ||
("TOKEN", None) | ||
] | ||
); | ||
let self_gone = secrets::delete(&o, &mine, "3kabc", Some("SELF"), None); | ||
assert_eq!(av.rt.block_on(self_gone).unwrap(), 1); | ||
| ||
// Deleted by name, for every runner; by runner; then the rest. | ||
let delete = |name: Option<&str>, runner: Option<&str>| { | ||
docs/design/runner.md+3−2
| @@ -754,8 +754,9 @@ open, or whose `refs` do not reach the ref, is not given. The file wins a | ||
name both grant, since an operator who grants one means it. An owner can | ||
give the hosted runner a secret without handing it to whoever runs it. | ||
An appview that does not answer makes the check `error`, as an unreadable | ||
file does. A runner that is also the repository's owner is listed every | ||
secret without its value, as owners are, so it uses its file. | ||
file does. A runner that logs in as the repository's owner is listed | ||
every secret, as owners are, with the values of those sealed to it, so it | ||
opens its own as any runner does. | ||
| ||
A secret reaches a step | ||
only if the workflow lists it, the file or the owner grants it to the repository and, | ||
docs/reference/api.md+1−1
| @@ -351,7 +351,7 @@ caller's PDS, else 401, and needs `--index`. | ||
| --- | --- | --- | --- | | ||
| `POST dev.knotless.putSecret` | service token, `lxm` this method | `repo` (a key: 1 to 32 letters and digits), `runner` (a DID), `name` (a shell variable's name, not starting `KNOTLESS_RUN`), `refs` (at most 16 `{pattern}`, each 1 to 256 bytes), `key` (a `did:key`), `sealed` (1 to 16465 bytes); any else 400 | `{}`; one of the same repository, runner and name is replaced | | ||
| `POST dev.knotless.deleteSecret` | service token, `lxm` this method | `repo`; `name`, `runner`, or both, to delete only those | `deleted`, how many of the caller's went | | ||
| `GET dev.knotless.listSecrets` | service token, `lxm` this method | `owner`, `repo` | `secrets`, by name then runner, each `name`, `runner`, `refs`, `key`, `updatedAt`: every one, without `sealed`, to the owner; those sealed to the caller, with `sealed`, to anyone else | | ||
| `GET dev.knotless.listSecrets` | service token, `lxm` this method | `owner`, `repo` | `secrets`, by name then runner, each `name`, `runner`, `refs`, `key`, `updatedAt`: every one to the owner, with `sealed` only on those sealed to it; those sealed to the caller, with `sealed`, to anyone else | | ||
| ||
A `subject` is a `com.atproto.admin.defs#repoRef` or a | ||
`com.atproto.repo.strongRef`, else 400. `getSubjectStatus` with neither | ||
lexicons/dev/knotless/listSecrets.json+1−1
| @@ -4,7 +4,7 @@ | ||
"defs": { | ||
"main": { | ||
"type": "query", | ||
"description": "The secrets dev.knotless.putSecret left for a repository, by name. Its owner sees every one, never its value. A runner sees those sealed to it, with the sealed value, to open with its key; anyone else, none. Requires a service token from the caller's PDS, audience the appview's DID, for this method.", | ||
"description": "The secrets dev.knotless.putSecret left for a repository, by name. Its owner sees every one, with the value only of those sealed to it, as a runner that logs in as the owner. A runner sees those sealed to it, with the sealed value, to open with its key; anyone else, none. Requires a service token from the caller's PDS, audience the appview's DID, for this method.", | ||
"parameters": { | ||
"type": "params", | ||
"required": ["owner", "repo"], | ||