redkite 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +343 -26
- package/dist/build.d.ts +2 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +11 -1
- package/dist/build.js.map +1 -1
- package/dist/checks.d.ts.map +1 -1
- package/dist/checks.js +4 -0
- package/dist/checks.js.map +1 -1
- package/dist/cli/agent.d.ts +2 -0
- package/dist/cli/agent.d.ts.map +1 -1
- package/dist/cli/agent.js +23 -1
- package/dist/cli/agent.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +15 -2
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +98 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -1
- package/dist/config.js.map +1 -1
- package/dist/deploy.d.ts +4 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +77 -23
- package/dist/deploy.js.map +1 -1
- package/dist/dockerfile.js +6 -7
- package/dist/dockerfile.js.map +1 -1
- package/dist/environment.d.ts +5 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +20 -0
- package/dist/environment.js.map +1 -0
- package/dist/host.d.ts +2 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +6 -0
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/localHost.d.ts.map +1 -1
- package/dist/localHost.js +2 -0
- package/dist/localHost.js.map +1 -1
- package/dist/plugin.d.ts +15 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +21 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugins/bitwarden.d.ts +11 -0
- package/dist/plugins/bitwarden.d.ts.map +1 -0
- package/dist/plugins/bitwarden.js +40 -0
- package/dist/plugins/bitwarden.js.map +1 -0
- package/dist/plugins/digitalOcean.d.ts +19 -0
- package/dist/plugins/digitalOcean.d.ts.map +1 -0
- package/dist/plugins/digitalOcean.js +71 -0
- package/dist/plugins/digitalOcean.js.map +1 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/rds.d.ts +14 -0
- package/dist/plugins/rds.d.ts.map +1 -0
- package/dist/plugins/rds.js +86 -0
- package/dist/plugins/rds.js.map +1 -0
- package/dist/plugins/snapshot.d.ts +7 -0
- package/dist/plugins/snapshot.d.ts.map +1 -0
- package/dist/plugins/snapshot.js +29 -0
- package/dist/plugins/snapshot.js.map +1 -0
- package/dist/presets/nodeApp.d.ts +1 -2
- package/dist/presets/nodeApp.d.ts.map +1 -1
- package/dist/presets/nodeApp.js +0 -1
- package/dist/presets/nodeApp.js.map +1 -1
- package/dist/recover.d.ts +19 -0
- package/dist/recover.d.ts.map +1 -0
- package/dist/recover.js +58 -0
- package/dist/recover.js.map +1 -0
- package/dist/secrets/store.d.ts +5 -2
- package/dist/secrets/store.d.ts.map +1 -1
- package/dist/secrets/store.js +25 -14
- package/dist/secrets/store.js.map +1 -1
- package/dist/source.d.ts +6 -1
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +12 -4
- package/dist/source.js.map +1 -1
- package/dist/sshHost.d.ts +2 -0
- package/dist/sshHost.d.ts.map +1 -1
- package/dist/sshHost.js +29 -11
- package/dist/sshHost.js.map +1 -1
- package/dist/steps.d.ts +0 -7
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +6 -3
- package/dist/steps.js.map +1 -1
- package/dist/types.d.ts +7 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/build.ts +12 -1
- package/src/checks.ts +4 -0
- package/src/cli/agent.ts +28 -1
- package/src/cli/config.ts +19 -2
- package/src/cli/index.ts +118 -29
- package/src/config.ts +27 -1
- package/src/deploy.ts +101 -29
- package/src/dockerfile.ts +7 -11
- package/src/environment.ts +24 -0
- package/src/host.ts +11 -0
- package/src/index.ts +4 -1
- package/src/localHost.ts +3 -0
- package/src/plugin.ts +50 -0
- package/src/plugins/bitwarden.ts +57 -0
- package/src/plugins/digitalOcean.ts +111 -0
- package/src/plugins/index.ts +4 -0
- package/src/plugins/rds.ts +126 -0
- package/src/plugins/snapshot.ts +44 -0
- package/src/presets/nodeApp.ts +1 -3
- package/src/recover.ts +90 -0
- package/src/secrets/store.ts +39 -20
- package/src/source.ts +20 -5
- package/src/sshHost.ts +35 -11
- package/src/steps.ts +7 -6
- package/src/types.ts +29 -12
- package/dist/secrets/bitwarden.d.ts +0 -3
- package/dist/secrets/bitwarden.d.ts.map +0 -1
- package/dist/secrets/bitwarden.js +0 -6
- package/dist/secrets/bitwarden.js.map +0 -1
- package/src/secrets/bitwarden.ts +0 -7
package/README.md
CHANGED
|
@@ -30,8 +30,10 @@ between deploys.
|
|
|
30
30
|
- [Requirements](#requirements)
|
|
31
31
|
- [Configuration](#configuration)
|
|
32
32
|
- [Hooks](#hooks)
|
|
33
|
+
- [Plugins](#plugins)
|
|
33
34
|
- [Verifying a build](#verifying-a-build)
|
|
34
35
|
- [CLI](#cli)
|
|
36
|
+
- [GitHub Actions](#github-actions)
|
|
35
37
|
- [How a deploy runs](#how-a-deploy-runs)
|
|
36
38
|
- [Design](#design)
|
|
37
39
|
- [Contributing](#contributing)
|
|
@@ -147,7 +149,14 @@ export default defineEnvironment({
|
|
|
147
149
|
});
|
|
148
150
|
```
|
|
149
151
|
|
|
150
|
-
Redkite finds them by name, so there is no list to keep in step, and
|
|
152
|
+
Redkite finds them by name, so there is no list to keep in step, and anything
|
|
153
|
+
beside the deployment whose name starts with `redkite` and is a module counts:
|
|
154
|
+
`redkite.staging.ts` and `redkite-staging.ts` name the same environment as
|
|
155
|
+
`redkite.staging.config.ts` does. One that was meant to be an environment and
|
|
156
|
+
is named slightly differently is refused rather than passed over as though it
|
|
157
|
+
were not there. The name has to be lower case, because it becomes part of an
|
|
158
|
+
image tag and a tag cannot hold a capital.
|
|
159
|
+
|
|
151
160
|
`redkite.config.ts` has no `environments` key at all: a second place to put a
|
|
152
161
|
set of them is a second place for them to disagree. A config that declares one
|
|
153
162
|
does not compile.
|
|
@@ -253,6 +262,28 @@ sits beside the deployment is refused too: it comes from one place or the other.
|
|
|
253
262
|
| `files` | Container path to the item whose contents land there |
|
|
254
263
|
| `volumes` | Volume name to container path, for state that outlives a deploy |
|
|
255
264
|
|
|
265
|
+
### What an app is built from
|
|
266
|
+
|
|
267
|
+
Every cloned app takes the environment's `branch` unless it says otherwise. An
|
|
268
|
+
app can name its own, and can pin instead of tracking:
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
{ name: "backend", repo: "…", branch: "release" } // tracks that branch
|
|
272
|
+
{ name: "worker", repo: "…", tag: "v1.2.3" } // pinned
|
|
273
|
+
{ name: "legacy", repo: "…", commit: "9f2b4c1" } // pinned
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
At most one of the three, and a config naming two is refused: they are
|
|
277
|
+
different commits and picking one is not redkite's to do.
|
|
278
|
+
|
|
279
|
+
`branch` is looked up under `refs/heads`, `tag` under `refs/tags` and peeled,
|
|
280
|
+
so an annotated tag answers with the commit it points at rather than with the
|
|
281
|
+
tag object. A `commit` is taken as it is and checked that it is one. The
|
|
282
|
+
failure says which kind was missing: *"acme/backend has no tag v9"*.
|
|
283
|
+
|
|
284
|
+
An environment can only say `branch`. A tag or a commit is a claim about one
|
|
285
|
+
repository, and an environment spans every app in the deployment.
|
|
286
|
+
|
|
256
287
|
### Building from a directory
|
|
257
288
|
|
|
258
289
|
An app names either a repository to clone or a directory already on this
|
|
@@ -276,7 +307,7 @@ the `branch` an environment names is not consulted at all.
|
|
|
276
307
|
|
|
277
308
|
The release is the content of the working tree, taken with git's own addressing
|
|
278
309
|
over a scratch index. It covers what is committed, what is modified and what is
|
|
279
|
-
untracked, and honours `.gitignore
|
|
310
|
+
untracked, and honours `.gitignore`, which is the same set the build reads. So
|
|
280
311
|
an edit you never committed is a new release and gets built, and a change under
|
|
281
312
|
an ignored `node_modules` is not and does not:
|
|
282
313
|
|
|
@@ -387,6 +418,25 @@ one lockfile for every package in it, so the install has to see all of them,
|
|
|
387
418
|
and `node_modules` is where that put it. An app with its own lockfile in a
|
|
388
419
|
subdirectory is not covered by `dir` alone.
|
|
389
420
|
|
|
421
|
+
### Reaching the deploy host
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
host: { bastion: "deploy@acme.example", hostKeys: "accept-new" }
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
The host's key is checked before anything is handed to it. `accept-new`, the
|
|
428
|
+
default, trusts it the first time and refuses it if the key ever changes after
|
|
429
|
+
that: no setup, and nothing to intercept once the first deploy has happened.
|
|
430
|
+
`strict` refuses any host not already in `known_hosts`, which is stronger and
|
|
431
|
+
means putting the key there yourself. `off` checks nothing, for a host whose
|
|
432
|
+
address is handed out again and again and only where nothing on the way to it
|
|
433
|
+
can listen.
|
|
434
|
+
|
|
435
|
+
ssh is never left able to ask a question, whichever of the three it is under: a
|
|
436
|
+
prompt nobody is there to answer is a deploy that hangs rather than one that
|
|
437
|
+
fails. Cloning is separate and always `accept-new`, because the deploy host
|
|
438
|
+
reaches GitHub rather than reaching you.
|
|
439
|
+
|
|
390
440
|
### Services
|
|
391
441
|
|
|
392
442
|
Long-lived containers shared by the apps. The proxy is not one of them: apps
|
|
@@ -428,13 +478,54 @@ An id is a pointer, not a credential, so it belongs in the config while the
|
|
|
428
478
|
credentials arrive at deploy time.
|
|
429
479
|
|
|
430
480
|
```ts
|
|
431
|
-
|
|
432
|
-
|
|
481
|
+
plugins: [bitwarden()],
|
|
482
|
+
// ...
|
|
483
|
+
secrets: bitwarden.item("00000000-0000-4000-8000-000000000001"),
|
|
484
|
+
files: { "/app/service-account.json": bitwarden.item("...") },
|
|
433
485
|
```
|
|
434
486
|
|
|
435
|
-
|
|
436
|
-
`
|
|
437
|
-
|
|
487
|
+
The vault is a [plugin](#plugins) like any other, so `bitwarden()` has to be
|
|
488
|
+
registered before `bitwarden.item()` resolves to anything. A deployment that
|
|
489
|
+
names a provider nothing registers is refused before it builds, rather than
|
|
490
|
+
reaching for a vault by name.
|
|
491
|
+
|
|
492
|
+
It unlocks with `BW_KEY`, a session obtained elsewhere, and falls back to
|
|
493
|
+
`BW_CLIENT_ID`, `BW_CLIENT_SECRET` and `BW_PASSWORD` when that is not set. A
|
|
494
|
+
config that would rather name its own variable passes the session in:
|
|
495
|
+
`bitwarden({ secrets: process.env.MY_VAULT_SESSION })`. One that reads no
|
|
496
|
+
secrets at all needs none of them: redkite only opens the stores your config
|
|
497
|
+
actually names.
|
|
498
|
+
|
|
499
|
+
#### Where a secret is, and where it is not
|
|
500
|
+
|
|
501
|
+
**Nothing a vault resolves is ever written into an image.** During the build it
|
|
502
|
+
is mounted as `.env` at the app's root for the length of each step and gone
|
|
503
|
+
after it, so a build can read a credential without shipping one, and no layer
|
|
504
|
+
ever holds it. Copying it in and deleting it later would not do: a deleted file
|
|
505
|
+
is still readable in the layer underneath.
|
|
506
|
+
|
|
507
|
+
At runtime it arrives as the container's own environment, written to the host
|
|
508
|
+
and handed to `docker create --env-file`, so no value appears in an argument
|
|
509
|
+
list and the file goes with the rest of the deploy's scratch. Read it from
|
|
510
|
+
`process.env`; there is no `.env` to read.
|
|
511
|
+
|
|
512
|
+
The same is true of the migrations and checks that run in the builder image:
|
|
513
|
+
they are given `--env-file` too, rather than finding a file the build left
|
|
514
|
+
behind.
|
|
515
|
+
|
|
516
|
+
If you do want one in the image, say so, in a build step where the mount is
|
|
517
|
+
still there:
|
|
518
|
+
|
|
519
|
+
```ts
|
|
520
|
+
steps: ["yarn build", "cp .env dist/.env"],
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
`files` is the other way to put a credential in an image on purpose, for the
|
|
524
|
+
ones that have to be a file rather than a variable:
|
|
525
|
+
|
|
526
|
+
```ts
|
|
527
|
+
files: { "/app/service-account.json": bitwarden.item("...") },
|
|
528
|
+
```
|
|
438
529
|
|
|
439
530
|
## Hooks
|
|
440
531
|
|
|
@@ -473,7 +564,7 @@ import { defineStep } from "redkite";
|
|
|
473
564
|
export default defineDeployment({
|
|
474
565
|
// ...
|
|
475
566
|
steps: [
|
|
476
|
-
defineStep("build:after:
|
|
567
|
+
defineStep("build:after:report", async (built, context) => {
|
|
477
568
|
for (const app of built.apps) {
|
|
478
569
|
context.task.detail(`${app.name} at ${app.release.slice(0, 7)}`);
|
|
479
570
|
}
|
|
@@ -563,37 +654,181 @@ defineStep("swap:before:seed", async (built, context) => {
|
|
|
563
654
|
});
|
|
564
655
|
```
|
|
565
656
|
|
|
566
|
-
###
|
|
657
|
+
### Snapshotting a database before a swap
|
|
567
658
|
|
|
568
|
-
A
|
|
569
|
-
|
|
659
|
+
A migration that goes wrong is the one thing a blue-green swap cannot undo:
|
|
660
|
+
putting the container back does not put the rows back. These take a snapshot
|
|
661
|
+
first, and they sit at `swap:before` so they run while the old containers are
|
|
662
|
+
still serving.
|
|
570
663
|
|
|
571
664
|
```ts
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
665
|
+
steps: [
|
|
666
|
+
// Above the migrate, because steps run in the order they are listed
|
|
667
|
+
rdsSnapshot({ instance: "acme-production", region: "eu-west-1" }),
|
|
668
|
+
migrate({ app: "backend", command: "yarn db:migrate" }),
|
|
669
|
+
]
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
`rdsSnapshot` goes through the AWS CLI, which every runner already has with the
|
|
673
|
+
credentials the job was given; signing a request by hand is a page of crypto
|
|
674
|
+
that nothing here could check. It takes an `instance`, or a `cluster` for
|
|
675
|
+
Aurora, and refuses a config naming both. RDS captures the data when the
|
|
676
|
+
snapshot begins rather than when it finishes, so it does not wait by default:
|
|
677
|
+
`wait: true` turns a snapshot that silently failed into a deploy that stops
|
|
678
|
+
before the migration, at the cost of however long the snapshot takes.
|
|
679
|
+
|
|
680
|
+
```ts
|
|
681
|
+
digitalOceanSnapshot({ volume: "e7f8...", tokenFrom: "DIGITALOCEAN_TOKEN" })
|
|
582
682
|
```
|
|
583
683
|
|
|
584
|
-
|
|
585
|
-
|
|
684
|
+
DigitalOcean's managed databases have no endpoint that takes a snapshot on
|
|
685
|
+
demand: their backups are automatic and the API only lists them. So what this
|
|
686
|
+
snapshots is the block storage `volume` the data sits on, which for redkite's
|
|
687
|
+
own postgres service is the disk under the container, or the `droplet` when the
|
|
688
|
+
database is the whole machine. A volume snapshot of a running Postgres is crash
|
|
689
|
+
consistent rather than clean, which Postgres is built to survive.
|
|
690
|
+
|
|
691
|
+
The token is named rather than given: a config is committed and a token is not.
|
|
692
|
+
Both plugins check what they can before the run starts, so a missing token or a
|
|
693
|
+
config naming two databases fails while the host is still untouched.
|
|
694
|
+
|
|
695
|
+
## Plugins
|
|
696
|
+
|
|
697
|
+
A plugin is what a deployment opts into. It adds steps to the run, or teaches
|
|
698
|
+
it to resolve a kind of secret, and **nothing it carries happens until the
|
|
699
|
+
config lists it** in `plugins`. Redkite's own vault is one of these rather than
|
|
700
|
+
something wired in behind them, so the rule has no exceptions to remember.
|
|
586
701
|
|
|
587
702
|
```ts
|
|
588
|
-
|
|
589
|
-
if (!webhook) throw new Error("SLACK_WEBHOOK is not set");
|
|
703
|
+
import { bitwarden, defineDeployment, digitalOceanSnapshot, rdsSnapshot } from "redkite";
|
|
590
704
|
|
|
591
705
|
export default defineDeployment({
|
|
706
|
+
project: "acme",
|
|
707
|
+
plugins: [
|
|
708
|
+
bitwarden(),
|
|
709
|
+
rdsSnapshot({ instance: "acme-production", region: "eu-west-1" }),
|
|
710
|
+
],
|
|
592
711
|
// ...
|
|
593
|
-
steps: [...slack(webhook)],
|
|
594
712
|
});
|
|
595
713
|
```
|
|
596
714
|
|
|
715
|
+
`plan` prints what a deployment opted into and where each plugin's steps land,
|
|
716
|
+
so what a run will do is readable without running it:
|
|
717
|
+
|
|
718
|
+
```
|
|
719
|
+
plugins
|
|
720
|
+
bitwarden 0 steps resolves bitwarden
|
|
721
|
+
rds-snapshot-acme-db 1 step
|
|
722
|
+
|
|
723
|
+
pipeline (deploy)
|
|
724
|
+
setup redkite
|
|
725
|
+
build redkite
|
|
726
|
+
swap:before:snapshot-acme-db rds-snapshot-acme-db
|
|
727
|
+
swap:before:migrate-backend
|
|
728
|
+
swap redkite
|
|
729
|
+
cleanup redkite
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
A plugin's steps run above the deployment's own, which is why the snapshot
|
|
733
|
+
lands before the migration written under `steps`. Registering the same plugin
|
|
734
|
+
twice is refused, and so is a second plugin claiming a provider another already
|
|
735
|
+
resolves.
|
|
736
|
+
|
|
737
|
+
The ones redkite ships are `bitwarden()`, [`rdsSnapshot()` and
|
|
738
|
+
`digitalOceanSnapshot()`](#snapshotting-a-database-before-a-swap). None of them
|
|
739
|
+
is on unless you say so.
|
|
740
|
+
|
|
741
|
+
### Writing plugins
|
|
742
|
+
|
|
743
|
+
A plugin is an object with a name, and steps or stores. `definePlugin` is
|
|
744
|
+
identity, but it checks the points where the plugin is written rather than
|
|
745
|
+
where it is registered, so a typo is the plugin's own failure:
|
|
746
|
+
|
|
747
|
+
```ts
|
|
748
|
+
import { definePlugin, defineStep, type Plugin } from "redkite";
|
|
749
|
+
|
|
750
|
+
export function announce(options: { url: string }): Plugin {
|
|
751
|
+
return definePlugin({
|
|
752
|
+
name: "announce",
|
|
753
|
+
steps: [
|
|
754
|
+
defineStep("swap:after:announce", async (input, context) => {
|
|
755
|
+
if (!input.ok) return input;
|
|
756
|
+
|
|
757
|
+
context.task.detail(`announcing ${input.released.join(", ")}`);
|
|
758
|
+
await fetch(options.url, { method: "POST", body: input.released.join(",") });
|
|
759
|
+
|
|
760
|
+
return input;
|
|
761
|
+
}),
|
|
762
|
+
],
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
The input and output types come from the point: a step at `swap:after` is
|
|
768
|
+
handed what the swap answered with, and must answer with the same, which is
|
|
769
|
+
what makes `input.released` typed without annotating anything.
|
|
770
|
+
|
|
771
|
+
A plugin resolving secrets registers a store per provider tag instead. It is
|
|
772
|
+
opened once, and only when a ref actually names that provider:
|
|
773
|
+
|
|
774
|
+
```ts
|
|
775
|
+
definePlugin({
|
|
776
|
+
name: "onepassword",
|
|
777
|
+
stores: {
|
|
778
|
+
onepassword: async ({ detail }) => {
|
|
779
|
+
detail("unlocking");
|
|
780
|
+
return { read: async (id: string) => await read(id) };
|
|
781
|
+
},
|
|
782
|
+
},
|
|
783
|
+
});
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
Then a ref pointing at it is `{ provider: "onepassword", id }`, which is what a
|
|
787
|
+
helper like `bitwarden.item()` answers with.
|
|
788
|
+
|
|
789
|
+
### As a separate package
|
|
790
|
+
|
|
791
|
+
There is nothing to register: a package exports a function, a config imports it
|
|
792
|
+
and lists what it answers with. The one thing to know is that **a plugin has to
|
|
793
|
+
ship JavaScript**. Node strips types from a config file, but it refuses to do
|
|
794
|
+
so for anything under `node_modules`, so a package shipping `.ts` fails to load
|
|
795
|
+
with `Stripping types is currently unsupported for files under node_modules`.
|
|
796
|
+
Compile it and ship `dist`, the way redkite itself does:
|
|
797
|
+
|
|
798
|
+
```json
|
|
799
|
+
{
|
|
800
|
+
"name": "redkite-plugin-announce",
|
|
801
|
+
"type": "module",
|
|
802
|
+
"main": "./dist/index.js",
|
|
803
|
+
"types": "./dist/index.d.ts",
|
|
804
|
+
"files": ["dist"],
|
|
805
|
+
"scripts": { "build": "tsc index.ts --outDir dist --declaration" },
|
|
806
|
+
"peerDependencies": { "redkite": ">=0.1.7" }
|
|
807
|
+
}
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
`redkite` belongs in `peerDependencies` rather than `dependencies`: a plugin
|
|
811
|
+
extends the redkite the deployment is already running, and a second copy of it
|
|
812
|
+
would be a second set of types that do not match.
|
|
813
|
+
|
|
814
|
+
```sh
|
|
815
|
+
npm install redkite-plugin-announce
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
```ts
|
|
819
|
+
import { announce } from "redkite-plugin-announce";
|
|
820
|
+
|
|
821
|
+
plugins: [announce({ url: process.env.SLACK_WEBHOOK ?? "" })],
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
A complete one is in [examples/plugin](examples/plugin). Two things worth
|
|
825
|
+
copying from it: take what the plugin needs as options rather than reading the
|
|
826
|
+
environment at import time, and name the variable a token comes from rather
|
|
827
|
+
than the token itself, so a config stays committable. Anything a plugin can
|
|
828
|
+
check about its own configuration it should check when it is constructed, so a
|
|
829
|
+
mistake is a config that fails to load rather than a deploy that stops with the
|
|
830
|
+
swap ahead of it.
|
|
831
|
+
|
|
597
832
|
## Verifying a build
|
|
598
833
|
|
|
599
834
|
`redkite verify` is the same host, the same services and the same images as a
|
|
@@ -664,6 +899,8 @@ redkite <command> [environment]
|
|
|
664
899
|
plan [environment] Print the derived topology, the pipeline and the nginx
|
|
665
900
|
deploy [environment] Build, swap, health check, and revert on failure
|
|
666
901
|
verify [environment] Bring the services up, build, and run each app's checks
|
|
902
|
+
rollback [environment] Put back any app a run moved and did not finish
|
|
903
|
+
down [environment] Stop everything this environment named
|
|
667
904
|
|
|
668
905
|
--config <path> Defaults to redkite.config.ts at the root of the project
|
|
669
906
|
--local Build the images here and ship them to the host
|
|
@@ -767,6 +1004,86 @@ the CPU and disk it is using. Nothing will clean up after it but you.
|
|
|
767
1004
|
|
|
768
1005
|
The sixth press leaves.
|
|
769
1006
|
|
|
1007
|
+
## GitHub Actions
|
|
1008
|
+
|
|
1009
|
+
There is a composite action in this repository. `verify` on a pull request,
|
|
1010
|
+
`deploy` on merge:
|
|
1011
|
+
|
|
1012
|
+
```yaml
|
|
1013
|
+
- uses: actions/checkout@v4
|
|
1014
|
+
- uses: JVKdouk/redkite@v1
|
|
1015
|
+
with:
|
|
1016
|
+
command: deploy
|
|
1017
|
+
environment: production
|
|
1018
|
+
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
|
1019
|
+
env:
|
|
1020
|
+
BW_CLIENT_ID: ${{ secrets.BW_CLIENT_ID }}
|
|
1021
|
+
BW_CLIENT_SECRET: ${{ secrets.BW_CLIENT_SECRET }}
|
|
1022
|
+
BW_PASSWORD: ${{ secrets.BW_PASSWORD }}
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
Whole workflows are in [examples/actions](examples/actions). The action sets
|
|
1026
|
+
Node up, caches `~/.cache/redkite` so the pinned Bitwarden CLI is installed once
|
|
1027
|
+
rather than every run, loads the key into an agent for the job, and runs a
|
|
1028
|
+
pinned `redkite`.
|
|
1029
|
+
|
|
1030
|
+
The view stands down on its own: it wants a terminal on both stdout and stdin,
|
|
1031
|
+
and a runner has neither, so what a job logs is one line per event.
|
|
1032
|
+
|
|
1033
|
+
A runner's `known_hosts` is empty every time, so the default `accept-new`
|
|
1034
|
+
trusts the deploy host on first sight each run. `hostKeys: "strict"` there means
|
|
1035
|
+
writing the key into `~/.ssh/known_hosts` before the deploy step.
|
|
1036
|
+
|
|
1037
|
+
**The key is only needed where something uses it.** A run that reaches a deploy
|
|
1038
|
+
host, or clones over ssh, wants an agent holding one. A `verify` that builds
|
|
1039
|
+
what the checkout already holds wants nothing: no host to reach, no clone. That
|
|
1040
|
+
is what makes a pull request from a fork's branch testable without handing the
|
|
1041
|
+
job a deploy key.
|
|
1042
|
+
|
|
1043
|
+
**Build on the host, not on the runner.** The obvious move is to point an app at
|
|
1044
|
+
the checkout the job already has, and it is usually the wrong one: a runner is
|
|
1045
|
+
thrown away, so BuildKit starts cold every time and the finished image has to be
|
|
1046
|
+
shipped over ssh. An app that names a `repo` is cloned by the deploy host into a
|
|
1047
|
+
mirror that is already warm, and nothing crosses the wire. Keep `path` for
|
|
1048
|
+
`verify`, where the point is to test the tree in the pull request including what
|
|
1049
|
+
was never pushed.
|
|
1050
|
+
|
|
1051
|
+
**Two runs would race.** Redkite holds no lock, so give the deploy job a
|
|
1052
|
+
`concurrency` group. Leave `cancel-in-progress` false on that one: a deploy
|
|
1053
|
+
interrupted between retiring the old container and starting the new one is the
|
|
1054
|
+
one state nothing downstream can reason about.
|
|
1055
|
+
|
|
1056
|
+
### Cancelling a run
|
|
1057
|
+
|
|
1058
|
+
A run that is **asked** to stop puts back whatever it moved. Everything from
|
|
1059
|
+
retiring the old container to the health check is one guarded stretch, and an
|
|
1060
|
+
abort anywhere in it reverts the apps that had already moved, on a connection
|
|
1061
|
+
the stop cannot refuse.
|
|
1062
|
+
|
|
1063
|
+
A run that is **killed** never gets that far, which is what a cancelled job is:
|
|
1064
|
+
SIGINT, then the job is torn down after a grace period. So the recovery has to
|
|
1065
|
+
be something a different process can do, reading what the host is in rather
|
|
1066
|
+
than what the dead run remembered. A retired container is the whole signal, and
|
|
1067
|
+
that is what `rollback` looks for:
|
|
1068
|
+
|
|
1069
|
+
```yaml
|
|
1070
|
+
- if: cancelled()
|
|
1071
|
+
uses: JVKdouk/redkite@v1
|
|
1072
|
+
with:
|
|
1073
|
+
command: rollback
|
|
1074
|
+
environment: production
|
|
1075
|
+
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
It does nothing when nothing was interrupted, so it is safe to leave in the
|
|
1079
|
+
workflow. `down` is its counterpart for an environment that exists to be built
|
|
1080
|
+
against rather than served from: it stops that environment's containers, the
|
|
1081
|
+
derived proxy included, and stops rather than removes them so the next run
|
|
1082
|
+
adopts them where it left off.
|
|
1083
|
+
|
|
1084
|
+
The build itself is still the one thing a killed job cannot take back with it:
|
|
1085
|
+
it keeps going on the deploy host. Nothing inside the job can change that.
|
|
1086
|
+
|
|
770
1087
|
## How a deploy runs
|
|
771
1088
|
|
|
772
1089
|
Everything happens on the deploy host, over a single multiplexed ssh connection
|
package/dist/build.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Docker } from "./docker.js";
|
|
2
|
+
import type { Ref } from "./source.js";
|
|
2
3
|
import type { Host } from "./host.js";
|
|
3
4
|
import type { AppTopology } from "./topology.js";
|
|
4
5
|
import type { AppSpec } from "./types.js";
|
|
@@ -23,5 +24,6 @@ export type BuildResult = {
|
|
|
23
24
|
builderTag: string;
|
|
24
25
|
cached: boolean;
|
|
25
26
|
};
|
|
27
|
+
export declare function refOf(app: AppSpec, branch: string): Ref;
|
|
26
28
|
export declare function build(app: AppSpec, topology: AppTopology, context: BuildContext): Promise<BuildResult>;
|
|
27
29
|
//# sourceMappingURL=build.d.ts.map
|
package/dist/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAM1C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzC,GAAG,EAAE,MAAM,CAAC;IAEZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAOF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAEhB,WAAW,EAAE,MAAM,CAAC;IAEpB,GAAG,EAAE,MAAM,CAAC;IAIZ,UAAU,EAAE,MAAM,CAAC;IAEnB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAM1C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzC,GAAG,EAAE,MAAM,CAAC;IAEZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAOF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAEhB,WAAW,EAAE,MAAM,CAAC;IAEpB,GAAG,EAAE,MAAM,CAAC;IAIZ,UAAU,EAAE,MAAM,CAAC;IAEnB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAKF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,CAKvD;AAED,wBAAsB,KAAK,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC,CAuFtB"}
|
package/dist/build.js
CHANGED
|
@@ -6,6 +6,16 @@ import { prepareSource } from "./source.js";
|
|
|
6
6
|
// below is what tells a host it already holds an image, and a host that trusts
|
|
7
7
|
// the commit alone serves the last pipeline's output forever
|
|
8
8
|
const PIPELINE = "4";
|
|
9
|
+
// The app's own, or the environment's branch when it names none. A branch is
|
|
10
|
+
// the only thing an environment can say, because a tag or a commit is a claim
|
|
11
|
+
// about one repository and an environment spans every app
|
|
12
|
+
export function refOf(app, branch) {
|
|
13
|
+
if (app.tag)
|
|
14
|
+
return { kind: "tag", name: app.tag };
|
|
15
|
+
if (app.commit)
|
|
16
|
+
return { kind: "commit", name: app.commit };
|
|
17
|
+
return { kind: "branch", name: app.branch ?? branch };
|
|
18
|
+
}
|
|
9
19
|
export async function build(app, topology, context) {
|
|
10
20
|
const { host, docker } = context;
|
|
11
21
|
const spec = app.build;
|
|
@@ -17,7 +27,7 @@ export async function build(app, topology, context) {
|
|
|
17
27
|
// against the deployment file rather than wherever this was run
|
|
18
28
|
path: app.path && resolve(app.path),
|
|
19
29
|
include: app.include,
|
|
20
|
-
|
|
30
|
+
ref: refOf(app, context.branch),
|
|
21
31
|
submodules: spec.submodules,
|
|
22
32
|
detail,
|
|
23
33
|
});
|
package/dist/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
|
package/dist/checks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAapE,wBAAsB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAajF;AAiCD,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,QAOzC"}
|
package/dist/checks.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { envFlags } from "./environment.js";
|
|
1
2
|
import { appRoot } from "./layout.js";
|
|
2
3
|
import { quote } from "./shell.js";
|
|
3
4
|
import { attachment, builderOf } from "./steps.js";
|
|
@@ -24,6 +25,9 @@ async function checkApp(app, spec, input, context) {
|
|
|
24
25
|
const flags = [
|
|
25
26
|
"run --rm",
|
|
26
27
|
...attachment(spec.network ?? "deployment", context.topology),
|
|
28
|
+
// Before the named settings, so a check can override what the vault says
|
|
29
|
+
// without editing the vault
|
|
30
|
+
...(await envFlags(app, context)),
|
|
27
31
|
`--workdir ${appRoot(app.dir)}`,
|
|
28
32
|
...settings({ ...app.environment, ...spec.environment }),
|
|
29
33
|
builderOf(input, app.name),
|
package/dist/checks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGnD,4EAA4E;AAC5E,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,0EAA0E;AAE1E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAY,EAAE,OAAgB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,SAAS;QAE1B,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,4DAA4D;IAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,IAAgB,EAAE,KAAY,EAAE,OAAgB;IACpF,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC;QAC7D,aAAa,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QAC/B,GAAG,QAAQ,CAAC,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACxD,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC;KAC3B,CAAC;IAEF,4EAA4E;IAC5E,qEAAqE;IACrE,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAE/C,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAC7B,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC7C,GAAG,GAAG,CAAC,IAAI,WAAW,OAAO,EAAE,EAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAClB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,WAAmC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAEvD,MAAM,IAAI,KAAK,CACb,2DAA2D;QACzD,0DAA0D,CAC7D,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGnD,4EAA4E;AAC5E,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,0EAA0E;AAE1E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAY,EAAE,OAAgB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,SAAS;QAE1B,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,4DAA4D;IAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,IAAgB,EAAE,KAAY,EAAE,OAAgB;IACpF,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC;QAC7D,yEAAyE;QACzE,4BAA4B;QAC5B,GAAG,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACjC,aAAa,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QAC/B,GAAG,QAAQ,CAAC,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACxD,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC;KAC3B,CAAC;IAEF,4EAA4E;IAC5E,qEAAqE;IACrE,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAE/C,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAC7B,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC7C,GAAG,GAAG,CAAC,IAAI,WAAW,OAAO,EAAE,EAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAClB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,WAAmC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAEvD,MAAM,IAAI,KAAK,CACb,2DAA2D;QACzD,0DAA0D,CAC7D,CAAC;AACJ,CAAC"}
|
package/dist/cli/agent.d.ts
CHANGED
package/dist/cli/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAIjE;AAWD,wBAAgB,YAAY,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,UA4B3D"}
|
package/dist/cli/agent.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { environmentOf } from "../config.js";
|
|
2
3
|
// Cloning private repositories and opening the tunnel both go through the
|
|
3
4
|
// agent, so a deploy without one fails halfway rather than at the start
|
|
5
|
+
// Asked before one is demanded. A runner has no keys and no way to be prompted
|
|
6
|
+
// for one, and a deployment that reaches no other machine and clones nothing
|
|
7
|
+
// has no use for an agent: insisting on one there is a green run turned red
|
|
8
|
+
export function needsAgent(config, environment) {
|
|
9
|
+
if (environmentOf(config, environment)?.host?.bastion)
|
|
10
|
+
return true;
|
|
11
|
+
return config.apps.some((app) => app.repo !== undefined && overSsh(app.repo));
|
|
12
|
+
}
|
|
13
|
+
// A clone URL that names a transport of its own carries its own credentials.
|
|
14
|
+
// Anything else is the scp-like form, which is ssh and wants a key
|
|
15
|
+
function overSsh(repo) {
|
|
16
|
+
return !/^(https?|git|file):\/\//.test(repo);
|
|
17
|
+
}
|
|
4
18
|
// A plain writer rather than a Log, because this runs before the view opens:
|
|
5
19
|
// ssh-add may ask for a passphrase, and it cannot ask through a screen
|
|
6
20
|
// something else is drawing
|
|
@@ -18,7 +32,15 @@ export function requireAgent(warn) {
|
|
|
18
32
|
if (pid)
|
|
19
33
|
process.env["SSH_AGENT_PID"] = pid;
|
|
20
34
|
// Inherits stdio so a passphrase prompt reaches the person running this
|
|
21
|
-
|
|
35
|
+
try {
|
|
36
|
+
execFileSync("ssh-add", [], { stdio: "inherit" });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error("ssh-add found no key to load. This deployment reaches another machine " +
|
|
40
|
+
"or clones over ssh, so it needs an agent holding a key that can. On a " +
|
|
41
|
+
"runner, set one up before this step and leave SSH_AUTH_SOCK in the " +
|
|
42
|
+
"environment");
|
|
43
|
+
}
|
|
22
44
|
return socket;
|
|
23
45
|
}
|
|
24
46
|
//# sourceMappingURL=agent.js.map
|
package/dist/cli/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,0EAA0E;AAC1E,wEAAwE;AAExE,6EAA6E;AAC7E,uEAAuE;AACvE,4BAA4B;AAC5B,MAAM,UAAU,YAAY,CAAC,IAA+B;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;IACtC,IAAI,GAAG;QAAE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,GAAG,CAAC;IAE5C,wEAAwE;IACxE,YAAY,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,0EAA0E;AAC1E,wEAAwE;AAExE,+EAA+E;AAC/E,6EAA6E;AAC7E,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,MAAkB,EAAE,WAAmB;IAChE,IAAI,aAAa,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IAEnE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,6EAA6E;AAC7E,mEAAmE;AACnE,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,6EAA6E;AAC7E,uEAAuE;AACvE,4BAA4B;AAC5B,MAAM,UAAU,YAAY,CAAC,IAA+B;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;IACtC,IAAI,GAAG;QAAE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,GAAG,CAAC;IAE5C,wEAAwE;IACxE,IAAI,CAAC;QACH,YAAY,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,wEAAwE;YACtE,wEAAwE;YACxE,qEAAqE;YACrE,aAAa,CAChB,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/cli/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAmC3D,wBAAsB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAiBvE;AA0CD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwB7C;AAGD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,wCA4BvD"}
|