~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A runner that logs in as the owner opens the secrets sealed to it

Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:run/owner-runner-secrets
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"],