Skip to content

Commit 9279116

Browse files
authored
Merge pull request #4 from newrelic/mvick/full-conf-def
chore: CDD updates and cleanup
2 parents 2b51865 + 3fbdead commit 9279116

File tree

17 files changed

+1609
-178
lines changed

17 files changed

+1609
-178
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
namespace: newrelic
2+
name: com.newrelic.my_agent
3+
version: 0.1.0
4+
variables:
5+
k8s:
6+
version:
7+
description: "My Agent init container version"
8+
type: string
9+
default: "latest"
10+
required: false
11+
podLabelSelector:
12+
description: "Pod label selector"
13+
type: yaml
14+
default: { }
15+
required: false
16+
namespaceLabelSelector:
17+
description: "Namespace label selector"
18+
type: yaml
19+
default: { }
20+
required: false
21+
env:
22+
description: "environment variables to pass to My agent"
23+
type: yaml
24+
default: [ ]
25+
required: false
26+
health_env:
27+
description: "environment variables to pass to health sidecar"
28+
type: yaml
29+
default: [ ]
30+
required: false
31+
health_version:
32+
description: "health sidecar image version"
33+
type: string
34+
default: "latest"
35+
required: false
36+
deployment:
37+
k8s:
38+
health:
39+
interval: 30s
40+
initial_delay: 30s
41+
objects:
42+
instrumentation:
43+
apiVersion: newrelic.com/v1beta1
44+
kind: Instrumentation
45+
metadata:
46+
name: ${nr-sub:agent_id}
47+
namespace: ${nr-ac:namespace_agents}
48+
spec:
49+
agent:
50+
language: My
51+
image: newrelic/newrelic-myagent-init:${nr-var:version}
52+
env: ${nr-var:env}
53+
healthAgent:
54+
image: newrelic/k8s-apm-agent-health-sidecar:${nr-var:health_version}
55+
env: ${nr-var:health_env}
56+
podLabelSelector: ${nr-var:podLabelSelector}
57+
namespaceLabelSelector: ${nr-var:namespaceLabelSelector}

.github/workflows/test_action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ jobs:
1818
- name: Run Agent Metadata Action
1919
uses: ./
2020
with:
21+
agent-type: 'myagent'
22+
version: '1.0.0'
2123
cache: false

CLAUDE.md

Lines changed: 99 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@ The project follows standard Go conventions:
1818
│ └── main.go
1919
├── internal/ # Private application code
2020
│ ├── config/ # Configuration loading and file I/O
21-
│ │ ├── config.go
22-
│ │ ├── config_test.go
23-
│ │ └── integration_test.go
24-
│ └── models/ # Data structures
25-
│ └── models.go
21+
│ │ ├── definitions.go # Config file reading with schema encoding
22+
│ │ ├── definitions_test.go # Integration tests (33 tests)
23+
│ │ ├── env.go # Environment variable loading
24+
│ │ ├── env_test.go # Environment tests
25+
│ │ ├── metadata.go # Version and metadata loading
26+
│ │ └── metadata_test.go # Metadata tests
27+
│ └── models/ # Data structures with validation
28+
│ ├── models.go # Type definitions + custom unmarshalers
29+
│ └── models_test.go # Model validation tests (17 tests)
2630
├── .fleetControl/ # Configuration files
2731
│ ├── configurationDefinitions.yml
32+
│ ├── agentControl/
33+
│ │ └── agent-schema-for-agent-control.yml
2834
│ └── schemas/
2935
│ └── myagent-config.json
3036
├── action.yml # GitHub Action definition
@@ -63,29 +69,69 @@ export GITHUB_WORKSPACE=/path/to/repo
6369
### Package Organization
6470

6571
**cmd/agent-metadata-action/main.go**: Application entry point
66-
- Loads workspace path via `config.LoadEnv()`
67-
- Calls `config.ReadConfigurationDefinitions()` to read and parse YAML
68-
- Marshals results to JSON for output
72+
- Loads workspace path via `config.LoadEnv()` (returns empty string if not set)
73+
- Loads metadata via `config.LoadMetadata()` (version, features, bugs, security)
74+
- If workspace is set (agent repo flow):
75+
- Reads configuration definitions via `config.ReadConfigurationDefinitions()`
76+
- Reads agent control via `config.LoadAndEncodeAgentControl()`
77+
- Combines into `AgentMetadata` structure
78+
- If workspace not set (docs flow):
79+
- Only outputs metadata
80+
- Uses `printJSON()` helper to marshal and output data
6981
- Uses GitHub Actions annotation format for logging (`::error::`, `::notice::`, `::debug::`)
7082

71-
**internal/config**: Configuration file I/O
72-
- `LoadEnv()`: Reads `GITHUB_WORKSPACE` environment variable
73-
- `ReadConfigurationDefinitions()`: Reads YAML file from local filesystem and parses it
74-
- Tests cover environment variable validation, file reading, and YAML parsing errors
75-
76-
**internal/models**: Data structures
77-
- `ConfigurationDefinition`: Represents a single configuration with fields like name, slug, platform, description, type, version, format, and schema
83+
**internal/config**: Configuration file I/O with three main modules:
84+
85+
1. **env.go**: Environment variable handling
86+
- `LoadEnv()`: Reads `GITHUB_WORKSPACE` (optional, returns empty string if not set)
87+
88+
2. **definitions.go**: Configuration file reading with security
89+
- `ReadConfigurationDefinitions()`: Reads and validates configuration YAML
90+
- `loadAndEncodeSchema()`: Loads schema files and base64-encodes them
91+
- Validates paths to prevent directory traversal attacks (rejects `..`)
92+
- Ensures resolved paths stay within `.fleetControl` directory
93+
- `LoadAndEncodeAgentControl()`: Reads and base64-encodes agent control YAML
94+
- Validates that `configurationDefinitions` array is not empty
95+
96+
3. **metadata.go**: Version and changelog metadata
97+
- `LoadMetadata()`: Loads version and changelog info from environment variables
98+
- `LoadVersion()`: Reads `INPUT_VERSION` with validation (format: X.Y.Z)
99+
- `parseCommaSeparated()`: Parses comma-separated lists (features, bugs, security)
100+
101+
**internal/models**: Data structures with validation
102+
- `ConfigurationDefinition`: Configuration with 8 required fields (validated via custom `UnmarshalYAML`)
103+
- Fields: slug, name, version, platform, description, type, format, schema
104+
- Custom unmarshaler validates all fields are present before accepting
105+
- `Metadata`: Version and changelog info (version required, validated via custom `UnmarshalYAML`)
106+
- `AgentControl`: Agent control content (platform and content required, validated via custom `UnmarshalJSON`)
78107
- `ConfigFile`: Root YAML structure containing `configurationDefinitions` array
79-
- `AgentMetadata`: (Currently unused - may be used for future service integration)
108+
- `AgentMetadata`: Complete metadata structure (configurationDefinitions + metadata + agentControl)
109+
- All validation happens at unmarshal time with clear error messages
80110

81111
### Data Flow
82112

113+
**Agent Repository Workflow** (GITHUB_WORKSPACE is set):
83114
1. `config.LoadEnv()` reads `GITHUB_WORKSPACE` environment variable
84-
2. `config.ReadConfigurationDefinitions()` constructs file path: `{workspace}/.fleetControl/configurationDefinitions.yml`
85-
3. `os.ReadFile()` reads the YAML file from local filesystem
86-
4. YAML is unmarshaled into `models.ConfigFile` structure
87-
5. Array of `ConfigurationDefinition` is returned
88-
6. Main function marshals each config to JSON and prints with `::debug::` annotations
115+
2. `config.LoadMetadata()` reads version and changelog from environment variables
116+
3. `config.ReadConfigurationDefinitions()` constructs file path: `{workspace}/.fleetControl/configurationDefinitions.yml`
117+
- Reads and parses YAML file
118+
- Custom `UnmarshalYAML` validates all required fields on each ConfigurationDefinition
119+
- Validates array is not empty
120+
- For each config, loads schema file and base64-encodes it:
121+
- Validates schema path (no `..`, must stay within `.fleetControl`)
122+
- Reads schema file
123+
- Base64-encodes content and replaces path with encoded content
124+
4. `config.LoadAndEncodeAgentControl()` reads `.fleetControl/agentControl/agent-schema-for-agent-control.yml`
125+
- Base64-encodes entire file content
126+
- Returns as single `AgentControl` entry with platform "all"
127+
5. Main constructs `AgentMetadata` combining configs, metadata, and agent control
128+
6. `printJSON()` marshals to JSON and prints with `::debug::` annotation
129+
130+
**Documentation Workflow** (GITHUB_WORKSPACE not set):
131+
1. `config.LoadEnv()` returns empty string
132+
2. `config.LoadMetadata()` reads version and changelog from environment variables
133+
3. Main outputs only the `Metadata` structure
134+
4. `printJSON()` marshals to JSON and prints with `::debug::` annotation
89135

90136
### GitHub Action Integration
91137

@@ -100,10 +146,38 @@ The action expects to run after `actions/checkout` which sets the `GITHUB_WORKSP
100146

101147
## Key Behaviors
102148

149+
### File Operations
103150
- Reads from **local filesystem** only (no network calls)
104-
- Requires `GITHUB_WORKSPACE` environment variable to be set
151+
- `GITHUB_WORKSPACE` is optional (enables agent repo flow when set, uses docs flow when empty)
152+
- Target file paths are hardcoded:
153+
- `.fleetControl/configurationDefinitions.yml`
154+
- `.fleetControl/agentControl/agent-schema-for-agent-control.yml`
155+
- Schema files are read from `.fleetControl/schemas/` (or subdirectories)
156+
157+
### Security
158+
- **Directory traversal protection**: Schema paths cannot contain `..`
159+
- **Path validation**: Resolved absolute paths must stay within `.fleetControl` directory
160+
- Multiple layers of validation prevent escaping the designated directory
161+
162+
### Validation
163+
- **All configuration fields are required**: name, slug, version, platform, description, type, format, schema
164+
- **Version format validation**: Must match `X.Y.Z` (three numeric components)
165+
- **Empty array rejection**: `configurationDefinitions` cannot be an empty array
166+
- **Validation timing**: All validation happens during YAML/JSON unmarshaling via custom unmarshalers
167+
- **Error messages**: Clear, contextual errors (e.g., "platform is required for config 'MyConfig'")
168+
169+
### Schema Handling
170+
- Schema files are automatically loaded and **base64-encoded**
171+
- Original relative paths (e.g., `./schemas/config.json`) are **replaced** with base64 content
172+
- Empty schema files are rejected
173+
174+
### Error Handling
105175
- Error output uses GitHub Actions annotation format: `::error::`, `::notice::`, `::debug::`
106176
- All errors result in exit code 1
107-
- Target file path is hardcoded: `.fleetControl/configurationDefinitions.yml`
108-
- YAML structure maps directly to JSON output (no transformation/filtering)
109-
- The `schema` field in configurations contains relative paths to JSON schema files
177+
- Error messages include context (file paths, config names)
178+
179+
### Testing
180+
- **50 total tests** across 2 packages (33 config integration tests, 17 model unit tests)
181+
- Tests use table-driven patterns for comprehensive coverage
182+
- Unit tests (models) focus on validation logic
183+
- Integration tests (config) focus on file I/O and wiring

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Add this action to your workflow after checking out your repository:
2020
2121
This action reads the `.fleetControl/configurationDefinitions.yml` file from your repository and outputs the configuration definitions. The action expects the file to be present after the repository has been checked out.
2222

23-
### Example Workflow
23+
### Example Workflow For Releasing a New Agent Version
2424

2525
```yaml
2626
name: Process Agent Metadata
@@ -34,10 +34,35 @@ jobs:
3434
steps:
3535
- name: Checkout repository
3636
uses: actions/checkout@v4
37+
with:
38+
ref: v1.0.0 # the release tag for the version being released
3739
3840
- name: Read agent metadata
3941
uses: newrelic/agent-metadata-action@v1
4042
with:
43+
version: 1.0.0 # only required if different from ref tag
44+
cache: true # Optional: Enable Go build cache (default: true)
45+
```
46+
47+
### Example Workflow For Updating Docs Metadata on an Existing Agent Version
48+
49+
The docs header contains things like a bug fix list, a list of features, etc for the given agent version. These
50+
will be updated after the initial agent version has been created so checking out the agent repo is not required.
51+
52+
```yaml
53+
name: Process Agent Metadata
54+
on:
55+
push:
56+
branches: [main]
57+
58+
jobs:
59+
read-metadata:
60+
runs-on: ubuntu-latest
61+
steps:
62+
- name: Read agent metadata
63+
uses: newrelic/agent-metadata-action@v1
64+
with:
65+
version: 1.0.0 # required in the docs case
4166
cache: true # Optional: Enable Go build cache (default: true)
4267
```
4368

@@ -57,6 +82,10 @@ configurationDefinitions:
5782
schema: "./schemas/config-schema.json"
5883
```
5984

85+
**All fields are required.** The action validates each configuration entry and will fail with a clear error message if any required field is missing.
86+
87+
**Schema files** are automatically base64-encoded and embedded in the output. Schema paths must be relative to the `.fleetControl` directory and cannot use directory traversal (`..`) for security.
88+
6089
## Building
6190

6291
To build the action locally:

action.yml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11
name: 'Agent Metadata Action'
2-
description: 'Fetches agent configuration metadata from a checked-out repository'
2+
description: 'Fetches agent configuration metadata to create/update NEGP entities in NR'
33
inputs:
4+
agent-type:
5+
description: 'The type of agent in all lowercase eg. dotnet'
6+
required: true
7+
default: ''
8+
version:
9+
description: 'Agent version in strict semver format MAJOR.MINOR.PATCH (ex. 1.2.3)'
10+
required: true
11+
default: ''
12+
features:
13+
description: 'Comma-separated list of features to include in the agent (ex. feature1,feature2)'
14+
required: false
15+
default: ''
16+
bugs:
17+
description: 'Comma-separated list of bugs to exclude from the agent (ex. bug1,bug2)'
18+
required: false
19+
default: ''
20+
security:
21+
description: 'Comma-separated list of security fixes (ex. fix1,fix2)'
22+
required: false
23+
default: ''
424
cache:
525
description: 'Enable Go build cache'
626
required: false
@@ -17,6 +37,12 @@ runs:
1737
- name: Build and Run
1838
id: run-action
1939
shell: bash
40+
env:
41+
INPUT_AGENT_TYPE: ${{ inputs.agent-type }}
42+
INPUT_VERSION: ${{ inputs.version }}
43+
INPUT_FEATURES: ${{ inputs.features }}
44+
INPUT_BUGS: ${{ inputs.bugs }}
45+
INPUT_SECURITY: ${{ inputs.security }}
2046
run: |
2147
set -e
2248
cd ${{ github.action_path }}

0 commit comments

Comments
 (0)