Skip to content

Commit e64a572

Browse files
authored
feat: add artifacts flag (#101)
## Summary by Sourcery Allow users to selectively generate specific bootstrap artifacts via a new `--artifacts` flag, updating output logic across all modes and providing comprehensive documentation and tests for the feature New Features: - Introduce `--artifacts` CLI flag to specify which artifacts (genesis, keys, abis, subgraph, allocations) to generate - Add ArtifactFilter type and `parseArtifactList` function to parse and validate comma-separated artifact lists Enhancements: - Conditionally generate and output selected artifacts in screen, file, and Kubernetes modes based on the artifact filter - Integrate artifact filtering into the bootstrap command and validate input at argument parsing Documentation: - Document the `--artifacts` flag and selective artifact generation feature in README.md and add a dedicated SELECTIVE_ARTIFACTS.md guide Tests: - Add unit tests for artifact filter parsing and for selective artifact generation in screen and file outputs
1 parent c6e9b0d commit e64a572

File tree

8 files changed

+865
-65
lines changed

8 files changed

+865
-65
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Options:
4343
-a, --allocations <file> Path to a genesis allocations JSON file. (default: none)
4444
--abi-directory <path> Directory containing ABI JSON files to publish as ConfigMaps.
4545
--subgraph-hash-file <path> Path to a file containing the subgraph IPFS hash.
46+
--artifacts <list> Comma-separated list of artifacts to generate (genesis, keys, abis, subgraph, allocations). (default: all)
4647
-o, --outputType <type> Output target (screen, file, kubernetes). (default: "screen")
4748
--static-node-port <number> P2P port used for static-nodes enode URIs. (default: 30303)
4849
--static-node-discovery-port <number> Discovery port used for static-nodes enode URIs. (default: 30303)

SELECTIVE_ARTIFACTS.md

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# Selective Artifact Generation
2+
3+
This document describes the selective artifact generation feature that allows you to generate only specific artifacts when bootstrapping a Besu network.
4+
5+
## Overview
6+
7+
By default, the network-bootstrapper generates all artifacts:
8+
- **genesis**: Genesis configuration file
9+
- **keys**: Validator and faucet private keys and node identities
10+
- **abis**: Contract ABI ConfigMaps
11+
- **subgraph**: Subgraph hash ConfigMap
12+
- **allocations**: Account allocation ConfigMaps
13+
14+
The `--artifacts` flag allows you to specify which artifacts to generate, skipping others. This is useful for:
15+
16+
- **Security**: Omit private keys in production upgrades
17+
- **Performance**: Skip unnecessary artifacts when only updating specific configurations
18+
- **Flexibility**: Generate configuration needed for specific use cases (e.g., only ABIs for contract interactions)
19+
20+
## CLI Usage
21+
22+
### Generate only genesis and ABIs (no private keys)
23+
24+
```bash
25+
bun run src/index.ts generate --artifacts genesis,abis
26+
```
27+
28+
### Generate only subgraph and allocations
29+
30+
```bash
31+
bun run src/index.ts generate --artifacts subgraph,allocations
32+
```
33+
34+
### Generate only contract ABIs
35+
36+
```bash
37+
bun run src/index.ts generate --artifacts abis
38+
```
39+
40+
### Generate all artifacts (default)
41+
42+
```bash
43+
bun run src/index.ts generate
44+
# or explicitly specify all:
45+
bun run src/index.ts generate --artifacts genesis,keys,abis,subgraph,allocations
46+
```
47+
48+
## Artifact Types
49+
50+
- **genesis**: Besu genesis.json configuration including initial allocations
51+
- **keys**: Validator node private keys, addresses, enodes, and faucet account keys
52+
- **abis**: Contract ABI files published as ConfigMaps
53+
- **subgraph**: Subgraph IPFS hash ConfigMap
54+
- **allocations**: Per-account allocation ConfigMaps (separate from genesis)
55+
56+
## Kubernetes Deployment
57+
58+
The artifact selection works seamlessly with all output modes:
59+
60+
- **screen**: Only prints selected artifacts to console
61+
- **file**: Only writes selected artifact files to the output directory
62+
- **kubernetes**: Only creates ConfigMaps and Secrets for selected artifacts
63+
64+
Example with Kubernetes output:
65+
66+
```bash
67+
bun run src/index.ts generate \
68+
--outputType kubernetes \
69+
--artifacts genesis,abis,subgraph
70+
```
71+
72+
## Helm Chart Integration
73+
74+
To enable selective artifact generation in your Helm chart, add the `--artifacts` flag to the bootstrapper Job.
75+
76+
### Update your values.yaml
77+
78+
Add a new settings value:
79+
80+
```yaml
81+
settings:
82+
# ... existing settings ...
83+
84+
# Comma-separated list of artifacts to generate
85+
# Valid values: genesis, keys, abis, subgraph, allocations
86+
# Empty or omitted = all artifacts (default)
87+
artifacts: ""
88+
```
89+
90+
### Update your Job template
91+
92+
In your Helm chart's bootstrap job template (typically in `templates/bootstrap-job.yaml` or similar), add the `--artifacts` flag to the bootstrapper command args:
93+
94+
```yaml
95+
args:
96+
- generate
97+
# ... other args ...
98+
{{- with .Values.settings.artifacts }}
99+
- --artifacts={{ . }}
100+
{{- end }}
101+
# ... remaining args ...
102+
```
103+
104+
### Example: Safe Production Upgrade
105+
106+
For production upgrades where you want to regenerate configuration without exposing private keys:
107+
108+
```yaml
109+
# values.yaml
110+
settings:
111+
artifacts: "genesis,abis,subgraph" # Omit 'keys' and 'allocations'
112+
```
113+
114+
This generates:
115+
- Genesis configuration
116+
- Contract ABIs for smart contract interactions
117+
- Subgraph hash for indexing
118+
- **Excludes**: Private keys, validator keys, and account allocations
119+
120+
### Example: dApp Deployment Configuration
121+
122+
For deploying dApps that need allocations and subgraph but not node keys:
123+
124+
```yaml
125+
# values.yaml
126+
settings:
127+
artifacts: "subgraph,allocations"
128+
```
129+
130+
## Security Considerations
131+
132+
When omitting the `keys` artifact:
133+
- No validator private keys are generated or exposed
134+
- No faucet account private key is generated
135+
- Static nodes and enode information are still generated
136+
- Existing keys in Kubernetes secrets are preserved
137+
138+
### Recommended for Production
139+
140+
For maximum security in production:
141+
142+
```yaml
143+
settings:
144+
artifacts: "genesis,abis,subgraph"
145+
```
146+
147+
This ensures:
148+
- Private keys are never regenerated or exposed
149+
- Existing validator secrets remain unchanged
150+
- Only necessary configuration is updated
151+
- Full traceability of what was generated
152+
153+
## Use Cases
154+
155+
### 1. Initial Network Bootstrap
156+
157+
```bash
158+
# Generate everything for initial setup
159+
bun run src/index.ts generate --outputType kubernetes
160+
```
161+
162+
### 2. Configuration Update Only
163+
164+
```bash
165+
# Update genesis and ABIs without touching keys
166+
bun run src/index.ts generate \
167+
--outputType kubernetes \
168+
--artifacts genesis,abis
169+
```
170+
171+
### 3. Add Smart Contracts
172+
173+
```bash
174+
# Update only contract ABIs and subgraph
175+
bun run src/index.ts generate \
176+
--outputType kubernetes \
177+
--artifacts abis,subgraph \
178+
--abi-directory ./new-contracts/abi
179+
```
180+
181+
### 4. Re-allocate Accounts
182+
183+
```bash
184+
# Update account allocations
185+
bun run src/index.ts generate \
186+
--outputType kubernetes \
187+
--artifacts allocations \
188+
--allocations ./new-allocations.json
189+
```
190+
191+
## Output Format
192+
193+
When using selective artifacts, the output files and ConfigMaps will only include the selected artifact types:
194+
195+
```
196+
out/
197+
2025-11-11_12-30-45-123/
198+
genesis.json # Only if 'genesis' selected
199+
besu-node-validator-0-private-key # Only if 'keys' selected
200+
besu-node-validator-0-address # Only if 'keys' selected
201+
besu-node-validator-0-enode # Only if 'keys' selected
202+
besu-node-validator-0-pubkey # Only if 'keys' selected
203+
faucet-private-key # Only if 'keys' selected
204+
faucet-address # Only if 'keys' selected
205+
faucet-pubkey # Only if 'keys' selected
206+
abi-sample.json # Only if 'abis' selected
207+
subgraph.json # Only if 'subgraph' selected
208+
static-nodes.json # Always included
209+
```
210+
211+
Note: Static nodes are always generated regardless of artifact selection.
212+
213+
## Implementation Details
214+
215+
### Artifact Filter
216+
217+
The artifact filter is implemented as a boolean configuration object:
218+
219+
```typescript
220+
type ArtifactFilter = {
221+
genesis: boolean;
222+
keys: boolean;
223+
abis: boolean;
224+
subgraph: boolean;
225+
allocations: boolean;
226+
};
227+
```
228+
229+
### Parsing
230+
231+
The `--artifacts` flag accepts comma-separated values:
232+
233+
- Valid: `genesis,keys,abis`
234+
- Valid: `genesis, keys, abis` (whitespace is trimmed)
235+
- Invalid: `genesis,invalid-type` (error thrown)
236+
- Empty/omitted: All artifacts enabled
237+
238+
### Error Handling
239+
240+
Invalid artifact types throw an error with a helpful message:
241+
242+
```
243+
Invalid artifact kind: "invalid". Must be one of: genesis, keys, abis, subgraph, allocations
244+
```
245+
246+
## Testing
247+
248+
The feature includes comprehensive tests for:
249+
- Artifact filter parsing and validation
250+
- Screen output filtering
251+
- File output filtering
252+
- Kubernetes output filtering
253+
- Common use cases
254+
255+
Run tests with:
256+
257+
```bash
258+
bun test
259+
```
260+
261+
Run specific artifact tests with:
262+
263+
```bash
264+
bun test bootstrap.artifacts-filter.test.ts
265+
bun test bootstrap.selective-artifacts.test.ts
266+
```
267+
268+
## Backward Compatibility
269+
270+
The feature is fully backward compatible:
271+
- Default behavior (no `--artifacts` flag) generates all artifacts
272+
- Existing scripts and Helm charts continue to work without changes
273+
- New `--artifacts` flag is optional
274+
275+
## Questions & Support
276+
277+
For issues or questions about selective artifact generation:
278+
1. Check the tests in `bootstrap.artifacts-filter.test.ts` for usage examples
279+
2. Review the implementation in `bootstrap.artifacts-filter.ts`
280+
3. File an issue on the GitHub repository
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { describe, expect, test } from "bun:test";
2+
import {
3+
DEFAULT_ARTIFACT_FILTER,
4+
includesArtifact,
5+
parseArtifactList,
6+
} from "./bootstrap.artifacts-filter.ts";
7+
8+
describe("parseArtifactList", () => {
9+
test("returns all artifacts by default", () => {
10+
const filter = parseArtifactList("");
11+
expect(filter).toEqual(DEFAULT_ARTIFACT_FILTER);
12+
});
13+
14+
test("parses single artifact kind", () => {
15+
const filter = parseArtifactList("genesis");
16+
expect(filter.genesis).toBe(true);
17+
expect(filter.keys).toBe(false);
18+
expect(filter.abis).toBe(false);
19+
expect(filter.subgraph).toBe(false);
20+
expect(filter.allocations).toBe(false);
21+
});
22+
23+
test("parses multiple artifact kinds", () => {
24+
const filter = parseArtifactList("genesis,keys,abis");
25+
expect(filter.genesis).toBe(true);
26+
expect(filter.keys).toBe(true);
27+
expect(filter.abis).toBe(true);
28+
expect(filter.subgraph).toBe(false);
29+
expect(filter.allocations).toBe(false);
30+
});
31+
32+
test("handles whitespace around items", () => {
33+
const filter = parseArtifactList(" genesis , keys , abis ");
34+
expect(filter.genesis).toBe(true);
35+
expect(filter.keys).toBe(true);
36+
expect(filter.abis).toBe(true);
37+
expect(filter.subgraph).toBe(false);
38+
expect(filter.allocations).toBe(false);
39+
});
40+
41+
test("case insensitive parsing", () => {
42+
const filter = parseArtifactList("Genesis,KEYS,Abis");
43+
expect(filter.genesis).toBe(true);
44+
expect(filter.keys).toBe(true);
45+
expect(filter.abis).toBe(true);
46+
});
47+
48+
test("throws on invalid artifact kind", () => {
49+
expect(() => parseArtifactList("invalid")).toThrow(
50+
'Invalid artifact kind: "invalid"'
51+
);
52+
});
53+
54+
test("throws on partially valid list", () => {
55+
expect(() => parseArtifactList("genesis,invalid,keys")).toThrow(
56+
'Invalid artifact kind: "invalid"'
57+
);
58+
});
59+
60+
test("ignores empty strings in list", () => {
61+
const filter = parseArtifactList("genesis,,keys,");
62+
expect(filter.genesis).toBe(true);
63+
expect(filter.keys).toBe(true);
64+
expect(filter.abis).toBe(false);
65+
});
66+
});
67+
68+
describe("includesArtifact", () => {
69+
test("returns true for enabled artifacts", () => {
70+
const filter = parseArtifactList("genesis,keys");
71+
expect(includesArtifact(filter, "genesis")).toBe(true);
72+
expect(includesArtifact(filter, "keys")).toBe(true);
73+
});
74+
75+
test("returns false for disabled artifacts", () => {
76+
const filter = parseArtifactList("genesis");
77+
expect(includesArtifact(filter, "keys")).toBe(false);
78+
expect(includesArtifact(filter, "abis")).toBe(false);
79+
});
80+
});

0 commit comments

Comments
 (0)