Skip to content

Commit a09f0ba

Browse files
authored
fix: so many fixes (#33)
* fix: field to specify execution pvc * fix: use strings for pylonenv * fix: use strings for QuinceyEnv * fix: make component functions more static * fix: so many fixes * feat: add txcache * fix: make resources accessible * fix: pylon, postgres, and ethereum * fix: missed types * feat: erpc-proxy package * docs: readme and contributing * fix: types and config fixes (#40) * docs: readme updates
1 parent 135c538 commit a09f0ba

39 files changed

+3630
-378
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ go.work.sum
2323

2424
# env file
2525
.env
26+
27+
CLAUDE.md

CONTRIBUTING.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Repository Overview
6+
7+
This is a Pulumi component library for deploying Signet blockchain infrastructure to Kubernetes. It provides reusable infrastructure-as-code components for various blockchain services.
8+
9+
## Development Commands
10+
11+
```bash
12+
# Build all packages
13+
go build -v ./...
14+
15+
# Run all tests
16+
go test -v ./...
17+
18+
# Run tests for a specific package (example)
19+
go test -v ./pkg/builder
20+
21+
# Install/update dependencies
22+
go mod download
23+
go mod tidy
24+
25+
# Verify module dependencies
26+
go mod verify
27+
```
28+
29+
## Architecture
30+
31+
The repository follows a component-based architecture where each blockchain service is implemented as a self-contained Pulumi component under `pkg/`:
32+
33+
- **AWS Components** (`pkg/aws/`): IAM roles and Postgres database components
34+
- **Blockchain Services**:
35+
- `pkg/builder/`: Builder service for blockchain operations
36+
- `pkg/erpc-proxy/`: eRPC proxy for RPC load balancing and failover
37+
- `pkg/ethereum/`: Composite Ethereum node management
38+
- `pkg/ethereum/consensus/`: Ethereum consensus layer (beacon chain)
39+
- `pkg/ethereum/execution/`: Ethereum execution layer
40+
- `pkg/pylon/`: Pylon service component
41+
- `pkg/quincey/`: Quincey service component
42+
- `pkg/signet_node/`: Core Signet node component
43+
- `pkg/txcache/`: Transaction cache component
44+
- **Utilities** (`pkg/utils/`): Shared helper functions
45+
46+
### Component Structure Pattern
47+
48+
Each component follows this consistent structure:
49+
50+
#### Core Files (Required)
51+
1. **`types.go`** - Type definitions using dual-struct pattern:
52+
- Public structs with base Go types for external API
53+
- Internal structs with Pulumi types for resource creation
54+
- Conversion functions (`toInternal()`) between public and internal types
55+
2. **`[component].go`** - Main component implementation:
56+
- `New[Component]()` constructor function
57+
- Resource creation logic (ServiceAccount, ConfigMap, Deployment, Service)
58+
- Helper methods for accessing component outputs
59+
3. **`validation.go`** - Input validation logic:
60+
- `Validate()` methods for all argument structs
61+
- Field-level validation functions
62+
- Resource format validators (memory, CPU, etc.)
63+
4. **`validation_test.go`** - Comprehensive unit tests:
64+
- Table-driven tests for all validation functions
65+
- Coverage of valid and invalid cases
66+
- Proper error message assertions
67+
68+
#### Optional Files
69+
5. **`constants.go`** - Component-specific constants:
70+
- Component kind identifier
71+
- Resource name suffixes
72+
- Default values for optional fields
73+
- Environment variable names
74+
6. **`helpers.go`** - Utility functions specific to the component:
75+
- Complex data transformations
76+
- Custom marshaling logic
77+
- Component-specific business logic
78+
79+
### Key Design Patterns
80+
81+
#### 1. Dual-Struct Pattern
82+
All components use a dual-struct pattern to separate public API from internal implementation:
83+
```go
84+
// Public struct with base Go types
85+
type ComponentArgs struct {
86+
Namespace string
87+
Name string
88+
Config ConfigStruct
89+
}
90+
91+
// Internal struct with Pulumi types
92+
type componentArgsInternal struct {
93+
Namespace pulumi.StringInput
94+
Name pulumi.StringInput
95+
Config configStructInternal
96+
}
97+
98+
// Conversion function
99+
func (args ComponentArgs) toInternal() componentArgsInternal {
100+
return componentArgsInternal{
101+
Namespace: pulumi.String(args.Namespace),
102+
Name: pulumi.String(args.Name),
103+
Config: args.Config.toInternal(),
104+
}
105+
}
106+
```
107+
108+
#### 2. Component Registration Pattern
109+
```go
110+
func NewComponent(ctx *pulumi.Context, args ComponentArgs, opts ...pulumi.ResourceOption) (*Component, error) {
111+
// 1. Apply defaults to optional fields
112+
// 2. Validate arguments
113+
if err := args.Validate(); err != nil {
114+
return nil, fmt.Errorf("invalid component args: %w", err)
115+
}
116+
// 3. Convert to internal types
117+
internalArgs := args.toInternal()
118+
// 4. Register component
119+
component := &Component{}
120+
err := ctx.RegisterComponentResource(ComponentKind, args.Name, component)
121+
// 5. Create resources with pulumi.Parent(component)
122+
}
123+
```
124+
125+
#### 3. Resource Creation Pattern
126+
- Always create ServiceAccount first
127+
- Use consistent naming with suffixes (`-sa`, `-config`, `-deployment`, `-service`)
128+
- Apply standard labels using `utils.CreateResourceLabels()`
129+
- Set proper parent relationships with `pulumi.Parent(component)`
130+
131+
#### 4. Validation Pattern
132+
```go
133+
func (args *ComponentArgs) Validate() error {
134+
// Required field validation
135+
if args.Namespace == "" {
136+
return fmt.Errorf("namespace is required")
137+
}
138+
// Nested validation
139+
if err := args.Config.Validate(); err != nil {
140+
return fmt.Errorf("invalid config: %w", err)
141+
}
142+
// Range validation
143+
if args.Port < 0 || args.Port > 65535 {
144+
return fmt.Errorf("invalid port: %d", args.Port)
145+
}
146+
return nil
147+
}
148+
```
149+
150+
#### 5. Complex Component Composition
151+
Some components (like `ethereum` and `pylon`) compose other components:
152+
- The `ethereum` package creates both execution and consensus clients
153+
- The `pylon` package wraps an ethereum node with additional configuration
154+
- Use clear ownership and dependency chains between sub-components
155+
156+
### Best Practices for New Components
157+
158+
1. **Start with Types**: Define your public API in `types.go` first
159+
2. **Implement Validation Early**: Write validation logic and tests before resource creation
160+
3. **Use Constants**: Define all magic numbers and strings in `constants.go`
161+
4. **Follow Naming Conventions**:
162+
- Public types/functions: PascalCase
163+
- Internal types: camelCase with "Internal" suffix
164+
- File names: lowercase with underscores
165+
5. **Document Complex Logic**: Add comments for non-obvious transformations
166+
6. **Test Thoroughly**: Aim for 100% coverage of validation logic
167+
7. **Handle Errors Gracefully**: Wrap errors with context using `fmt.Errorf`
168+
8. **Consider Defaults**: Provide sensible defaults for optional fields
169+
9. **Support Configuration**: Use ConfigMaps for configuration, Secrets for sensitive data
170+
10. **Implement Health Checks**: Add liveness, readiness, and startup probes where applicable
171+
172+
## Testing Approach
173+
174+
- Unit tests focus on validation logic and helper functions
175+
- Test files use the `testify/assert` library for assertions
176+
- No integration tests - components are tested when used in actual Pulumi programs
177+
178+
## Adding New Components
179+
180+
When creating a new component:
181+
1. Create a new directory under `pkg/`
182+
2. Follow the standard file structure (types.go, component.go, validation.go, etc.)
183+
3. Implement the `New[Component]` function that returns a `ComponentResource`
184+
4. Add comprehensive validation for all inputs
185+
5. Write unit tests for validation logic
186+
6. Update imports in consuming Pulumi programs to use the new component
187+
188+
## Common Pitfalls
189+
190+
1. **Go Version**: CI uses Go 1.22, but go.mod specifies 1.24.3 - ensure compatibility
191+
2. **Pulumi Context**: Always use the provided `*pulumi.Context` for resource creation
192+
3. **Resource Dependencies**: Use Pulumi's dependency system via `pulumi.DependsOn` when needed
193+
4. **Kubernetes Namespaces**: Components don't create namespaces - they expect them to exist

0 commit comments

Comments
 (0)