Skip to content

Commit 696fc91

Browse files
authored
Mise github token (#159)
* ability to pass a github token to the mise install command * buildkit frontend docs
1 parent e36f8a9 commit 696fc91

File tree

9 files changed

+184
-24
lines changed

9 files changed

+184
-24
lines changed

buildkit/build.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type BuildWithBuildkitClientOptions struct {
3434
ImportCache string
3535
ExportCache string
3636
CacheKey string
37+
GitHubToken string
3738
}
3839

3940
func BuildWithBuildkitClient(appDir string, plan *plan.BuildPlan, opts BuildWithBuildkitClientOptions) error {
@@ -73,6 +74,7 @@ func BuildWithBuildkitClient(appDir string, plan *plan.BuildPlan, opts BuildWith
7374
BuildPlatform: buildPlatform,
7475
SecretsHash: opts.SecretsHash,
7576
CacheKey: opts.CacheKey,
77+
GitHubToken: opts.GitHubToken,
7678
})
7779
if err != nil {
7880
return fmt.Errorf("error converting plan to LLB: %w", err)

buildkit/build_llb/build_graph.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/moby/buildkit/util/system"
1313
specs "github.com/opencontainers/image-spec/specs-go/v1"
1414
"github.com/railwayapp/railpack/buildkit/graph"
15+
"github.com/railwayapp/railpack/core/generate"
1516
"github.com/railwayapp/railpack/core/plan"
1617
)
1718

@@ -22,6 +23,7 @@ type BuildGraph struct {
2223
Platform *specs.Platform
2324
LocalState *llb.State
2425

26+
githubToken string
2527
secretsFile *llb.State
2628
usedSecretsBase *llb.State
2729
}
@@ -31,7 +33,7 @@ type BuildGraphOutput struct {
3133
GraphEnv BuildEnvironment
3234
}
3335

34-
func NewBuildGraph(plan *plan.BuildPlan, localState *llb.State, cacheStore *BuildKitCacheStore, secretsHash string, platform *specs.Platform) (*BuildGraph, error) {
36+
func NewBuildGraph(plan *plan.BuildPlan, localState *llb.State, cacheStore *BuildKitCacheStore, secretsHash string, platform *specs.Platform, githubToken string) (*BuildGraph, error) {
3537
var secretsFile *llb.State
3638
if secretsHash != "" {
3739
st := llb.Scratch().File(llb.Mkfile("/secrets-hash", 0644, []byte(secretsHash)), llb.WithCustomName("[railpack] secrets hash"))
@@ -46,6 +48,7 @@ func NewBuildGraph(plan *plan.BuildPlan, localState *llb.State, cacheStore *Buil
4648
Platform: platform,
4749
LocalState: localState,
4850

51+
githubToken: githubToken,
4952
secretsFile: secretsFile,
5053
usedSecretsBase: &usedSecretsBase,
5154
}
@@ -271,7 +274,14 @@ func (g *BuildGraph) convertExecCommandToLLB(node *StepNode, cmd plan.ExecComman
271274
opts = append(opts, cacheOpts...)
272275
}
273276

277+
// If we have a GitHub token AND we are installing mise packages, we want to pass the GitHub token
278+
// It is important to validate the command so that we don't pass the token to other commands
279+
if g.githubToken != "" && cmd.Cmd == generate.MiseInstallCommand {
280+
opts = append(opts, llb.AddEnv("GITHUB_TOKEN", g.githubToken))
281+
}
282+
274283
s := state.Run(opts...).Root()
284+
275285
return s, nil
276286
}
277287

buildkit/convert.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,18 @@ import (
1515

1616
type ConvertPlanOptions struct {
1717
BuildPlatform BuildPlatform
18-
SecretsHash string
19-
CacheKey string
20-
SessionID string
18+
19+
// Hash of all the secrets values that can be used to invalidate the layer cache when a secret changes
20+
SecretsHash string
21+
22+
// Unique value prepended to all cache mount keys
23+
CacheKey string
24+
25+
// BuildKit session ID
26+
SessionID string
27+
28+
// Token used to make authenticated API requests to GitHub to increase rate limits
29+
GitHubToken string
2130
}
2231

2332
const (
@@ -35,7 +44,7 @@ func ConvertPlanToLLB(plan *p.BuildPlan, opts ConvertPlanOptions) (*llb.State, *
3544
)
3645

3746
cacheStore := build_llb.NewBuildKitCacheStore(opts.CacheKey)
38-
graph, err := build_llb.NewBuildGraph(plan, &localState, cacheStore, opts.SecretsHash, &platform)
47+
graph, err := build_llb.NewBuildGraph(plan, &localState, cacheStore, opts.SecretsHash, &platform, opts.GitHubToken)
3948
if err != nil {
4049
return nil, nil, err
4150
}

buildkit/frontend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const (
2828
secretsHash = "secrets-hash"
2929

3030
cacheKey = "cache-key"
31+
32+
githubToken = "github-token"
3133
)
3234

3335
func StartFrontend() {
@@ -46,6 +48,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
4648

4749
cacheKey := buildArgs[cacheKey]
4850
secretsHash := buildArgs[secretsHash]
51+
githubToken := buildArgs[githubToken]
4952

5053
// TODO: Support building for multiple platforms
5154
buildPlatform, err := validatePlatform(opts)
@@ -68,6 +71,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
6871
SecretsHash: secretsHash,
6972
CacheKey: cacheKey,
7073
SessionID: c.BuildOpts().SessionID,
74+
GitHubToken: githubToken,
7175
})
7276
if err != nil {
7377
return nil, fmt.Errorf("error converting plan to LLB: %w", err)

cli/build.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ var BuildCommand = &cli.Command{
6161
return nil
6262
}
6363

64-
serializedPlan, err := json.MarshalIndent(buildResult.Plan, "", " ")
65-
if err != nil {
66-
return cli.Exit(err, 1)
67-
}
68-
6964
if cmd.Bool("show-plan") {
65+
serializedPlan, err := json.MarshalIndent(buildResult.Plan, "", " ")
66+
if err != nil {
67+
return cli.Exit(err, 1)
68+
}
69+
7070
fmt.Println(string(serializedPlan))
7171
}
7272

@@ -91,6 +91,7 @@ var BuildCommand = &cli.Command{
9191
SecretsHash: secretsHash,
9292
Secrets: env.Variables,
9393
Platform: platform,
94+
GitHubToken: os.Getenv("GITHUB_TOKEN"),
9495
})
9596
if err != nil {
9697
return cli.Exit(err, 1)

core/generate/mise_step_builder.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
const (
1616
MisePackageStepName = "packages:mise"
17+
MiseInstallCommand = "sh -c 'mise trust -a && mise install'"
1718
)
1819

1920
type MiseStepBuilder struct {
@@ -174,7 +175,7 @@ func (b *MiseStepBuilder) Build(p *plan.BuildPlan, options *BuildStepOptions) er
174175
plan.NewFileCommand("/etc/mise/config.toml", "mise.toml", plan.FileOptions{
175176
CustomName: "create mise config",
176177
}),
177-
plan.NewExecCommand("sh -c 'mise trust -a && mise install'", plan.ExecOptions{
178+
plan.NewExecCommand(MiseInstallCommand, plan.ExecOptions{
178179
CustomName: "install mise packages: " + strings.Join(pkgNames, ", "),
179180
}),
180181
})

core/mise/mise.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ const (
2020
)
2121

2222
type Mise struct {
23-
binaryPath string
24-
cacheDir string
23+
binaryPath string
24+
cacheDir string
25+
githubToken string
2526
}
2627

2728
const (
@@ -34,9 +35,12 @@ func New(cacheDir string) (*Mise, error) {
3435
return nil, fmt.Errorf("failed to ensure mise is installed: %w", err)
3536
}
3637

38+
githubToken := os.Getenv("GITHUB_TOKEN")
39+
3740
return &Mise{
38-
binaryPath: binaryPath,
39-
cacheDir: cacheDir,
41+
binaryPath: binaryPath,
42+
cacheDir: cacheDir,
43+
githubToken: githubToken,
4044
}, nil
4145
}
4246

@@ -114,6 +118,10 @@ func (m *Mise) runCmd(args ...string) (string, error) {
114118
fmt.Sprintf("PATH=%s", os.Getenv("PATH")),
115119
)
116120

121+
if m.githubToken != "" {
122+
cmd.Env = append(cmd.Env, fmt.Sprintf("GITHUB_TOKEN=%s", m.githubToken))
123+
}
124+
117125
if err := cmd.Run(); err != nil {
118126
return "", fmt.Errorf("failed to run mise command '%s': %w\n%s\n\n%s",
119127
strings.Join(append([]string{m.binaryPath}, args...), " "),

docs/astro.config.mjs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,6 @@ export default defineConfig({
3838
{
3939
label: "Guides",
4040
items: [
41-
// {
42-
// label: "Building with CLI and BuildKit",
43-
// link: "/guides/building-with-cli",
44-
// },
45-
// {
46-
// label: "Building with a Custom Frontend",
47-
// link: "/guides/custom-frontend",
48-
// },
4941
{
5042
label: "Installing Additional Packages",
5143
link: "/guides/installing-packages",
@@ -92,7 +84,10 @@ export default defineConfig({
9284
},
9385
{
9486
label: "Reference",
95-
items: [{ label: "CLI Commands", link: "/reference/cli" }],
87+
items: [
88+
{ label: "CLI Commands", link: "/reference/cli" },
89+
{ label: "BuildKit Frontend", link: "/reference/frontend" },
90+
],
9691
},
9792
{
9893
label: "Architecture",
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
title: BuildKit Frontend Reference
3+
description: Complete reference for the Railpack BuildKit frontend
4+
---
5+
6+
Complete reference documentation for the Railpack BuildKit frontend. For a full example of how to use the frontend for a production build, see the [running railpack in production](../guides/running-railpack-in-production) guide.
7+
8+
## Expected
9+
10+
To use the Railpack BuildKit frontend, you must provide a build plan file (e.g.
11+
`railpack-plan.json`) generated by the `railpack prepare` command. This file
12+
describes how your app should be built and must be accessible to the build
13+
process.
14+
15+
**You must specify the path to the build plan file:**
16+
17+
For **Docker** (with BuildKit enabled):
18+
19+
```sh
20+
docker buildx build \
21+
--build-arg BUILDKIT_SYNTAX="ghcr.io/railwayapp/railpack-frontend" \
22+
-f /path/to/railpack-plan.json \
23+
/path/to/app/to/build
24+
```
25+
26+
For **BuildKit** directly:
27+
28+
```sh
29+
buildctl build \
30+
--local context=/path/to/app/to/build \
31+
--local dockerfile=/path/to/dir/containing/railpack-plan.json \
32+
--frontend=gateway.v0 \
33+
--opt source=ghcr.io/railwayapp/railpack:railpack-frontend \
34+
--output type=docker,name=test
35+
```
36+
37+
The build plan file does not need to be in the same directory as your app, but
38+
you must reference it correctly with the `-f` flag (Docker) or `--local
39+
dockerfile` (BuildKit).
40+
41+
## Configuration
42+
43+
You can pass advanced options to the frontend using the `--opt` flag (for BuildKit) or as `--build-arg` (for Docker). The following options are supported:
44+
45+
| Flag | Description | Default |
46+
| ---------------- | -------------------------------------------------------------------------------------- | ------- |
47+
| `--cache-key` | Unique ID to prefix to cache keys for cache invalidation. | |
48+
| `--secrets-hash` | Hash of all secret values, used to invalidate cache when secrets change. | |
49+
| `--github-token` | GitHub token to increase API rate limits for private repositories or package installs. | |
50+
51+
### Example
52+
53+
**Docker:**
54+
55+
```sh
56+
docker buildx build \
57+
--build-arg BUILDKIT_SYNTAX="ghcr.io/railwayapp/railpack-frontend" \
58+
--build-arg cache-key=my-key \
59+
--build-arg secrets-hash=abc123 \
60+
--build-arg github-token=ghp_xxx \
61+
--build-arg FOO=bar \
62+
-f /path/to/railpack-plan.json \
63+
/path/to/app/to/build
64+
```
65+
66+
**BuildKit:**
67+
68+
```sh
69+
buildctl build \
70+
--frontend=railwayapp/railpack \
71+
--opt cache-key=my-key \
72+
--opt secrets-hash=abc123 \
73+
--opt github-token=ghp_xxx \
74+
--opt build-arg:FOO=bar
75+
```
76+
77+
## Secrets
78+
79+
To use secrets in your build, you must:
80+
81+
1. Pass secret names to `railpack prepare` (so they are included in the build
82+
plan):
83+
84+
```sh
85+
railpack prepare /dir/to/build --env STRIPE_LIVE_KEY=sk_live_asdf
86+
```
87+
88+
2. Pass secret values to the build using Docker or BuildKit:
89+
90+
**Docker:**
91+
92+
```sh
93+
STRIPE_LIVE_KEY=asdfasdf docker buildx build \
94+
--build-arg BUILDKIT_SYNTAX="ghcr.io/railwayapp/railpack-frontend" \
95+
-f /path/to/railpack-plan.json \
96+
--secret id=STRIPE_LIVE_KEY,env=STRIPE_LIVE_KEY \
97+
/path/to/app/to/build
98+
```
99+
100+
**BuildKit:**
101+
102+
```sh
103+
buildctl build \
104+
--local context=/path/to/app/to/build \
105+
--local dockerfile=/path/to/dir/containing/railpack-plan.json \
106+
--frontend=gateway.v0 \
107+
--opt source=ghcr.io/railwayapp/railpack:railpack-frontend \
108+
--secret id=STRIPE_LIVE_KEY,env=STRIPE_LIVE_KEY \
109+
--output type=docker,name=test
110+
```
111+
112+
## Layer Invalidation
113+
114+
To ensure build layers are invalidated when secret values change, compute a hash
115+
of your secret values and pass it as a build argument:
116+
117+
```sh
118+
--build-arg secrets-hash=$(echo -n "STRIPE_LIVE_KEY=sk_live_asdf" | sha256sum | awk '{print $1}')
119+
```
120+
121+
This ensures the build cache is properly invalidated when secrets change.
122+
123+
## GitHub Token
124+
125+
If provided, the GitHub token is passed to Mise as the `GITHUB_TOKEN`
126+
([Docs](https://mise.jdx.dev/getting-started.html#github-api-rate-limiting)).
127+
This increases the rate limits when fetching info from the GitHub API.
128+
129+
Once passed, this token will be accessible to the build context, so you should
130+
not pass a token that the owner of the build code should not have access to.

0 commit comments

Comments
 (0)