Skip to content

Commit bfdf2e6

Browse files
Feature/ga bp envs (#62)
* wip * Add event-name and release tag * Add support for release-tag * PR info in push * Add debug logs * remove {} from authors for bitbucket * pipeline detection for pr * Always get author
1 parent 791b27b commit bfdf2e6

File tree

3 files changed

+259
-249
lines changed

3 files changed

+259
-249
lines changed

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ PyLynk automatically detects and captures CI/CD environment information when run
314314
### Automatic PR and Build Information Extraction
315315

316316
When running in a CI environment during SBOM uploads, PyLynk automatically extracts:
317+
- **Event Information**: Event type (pull_request, push, release), release tag (when applicable)
317318
- **Pull Request Information**: PR number, URL, source/target branches, **author** (when in PR context)
318319
- **Build Information**: Build ID, number, URL, commit SHA
319320
- **Repository Information**: Repository name, owner, URL
@@ -333,6 +334,8 @@ on:
333334
branches: [ main ]
334335
push:
335336
branches: [ main ]
337+
release:
338+
types: [ published ]
336339
337340
jobs:
338341
upload-sbom:
@@ -350,6 +353,8 @@ jobs:
350353
run: |
351354
python3 pylynk.py upload --prod 'my-product' --sbom sbom.json
352355
# PyLynk automatically captures:
356+
# - Event type (pull_request, push, or release)
357+
# - Release tag (for release events)
353358
# - PR number and branches (for pull_request events)
354359
# - PR author (GITHUB_ACTOR)
355360
# - Commit SHA and build URL
@@ -369,8 +374,17 @@ pipelines:
369374
script:
370375
- pip install -r requirements.txt
371376
- python3 pylynk.py upload --prod 'my-product' --sbom sbom.json
377+
tags:
378+
'v*':
379+
- step:
380+
name: Upload SBOM for Release
381+
script:
382+
- pip install -r requirements.txt
383+
- python3 pylynk.py upload --prod 'my-product' --sbom sbom.json
372384
# PyLynk automatically captures:
373-
# - PR ID and branches
385+
# - Event type (pull_request, push, or release)
386+
# - Release tag (for tag-triggered builds)
387+
# - PR ID and branches (for PR events)
374388
# - PR author (BITBUCKET_STEP_TRIGGERER_UUID)
375389
# - Build number and URL
376390
# - Repository information
@@ -385,6 +399,10 @@ PyLynk also supports generic CI environments by checking common environment vari
385399
| Variable | Description | Maps to Header |
386400
|----------|-------------|----------------|
387401
| `CI` | Set to `true` to indicate CI environment | Enables CI detection |
402+
| **Release Variables** | | |
403+
| `GIT_TAG` | Git tag for release builds | `X-Release-Tag` |
404+
| `CI_COMMIT_TAG` | GitLab CI tag variable | `X-Release-Tag` |
405+
| `TAG_NAME` | Alternative tag name variable | `X-Release-Tag` |
388406
| **Pull Request Variables** | | |
389407
| `PULL_REQUEST_NUMBER` | PR number | `X-PR-Number` |
390408
| `PR_NUMBER` | Alternative PR number variable | `X-PR-Number` |
@@ -488,6 +506,8 @@ The extracted CI information is sent as HTTP headers with upload API requests:
488506
| Header | Description | Example |
489507
|--------|-------------|---------|
490508
| `X-CI-Provider` | CI platform name | `github_actions`, `bitbucket_pipelines`, `generic_ci` |
509+
| `X-Event-Type` | CI event type | `pull_request`, `push`, `release` |
510+
| `X-Release-Tag` | Release tag name (when event is release) | `v1.2.3` |
491511
| `X-PR-Number` | Pull request number | `123` |
492512
| `X-PR-URL` | Pull request URL | `https://github.com/org/repo/pull/123` |
493513
| `X-PR-Source-Branch` | PR source branch | `feature/new-feature` |

pylynk/api/client.py

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,29 @@ def _get_headers(self):
115115
# Add as custom headers
116116
headers['X-CI-Provider'] = ci_metadata.get('ci_provider', 'unknown')
117117

118-
# Add PR information if available
119-
if 'pr' in ci_metadata:
120-
pr_info = ci_metadata['pr']
121-
if 'number' in pr_info:
122-
headers['X-PR-Number'] = str(pr_info['number'])
123-
if 'url' in pr_info:
124-
headers['X-PR-URL'] = pr_info['url']
125-
if 'source_branch' in pr_info:
126-
headers['X-PR-Source-Branch'] = pr_info['source_branch']
127-
if 'target_branch' in pr_info:
128-
headers['X-PR-Target-Branch'] = pr_info['target_branch']
129-
if 'author' in pr_info:
130-
headers['X-PR-Author'] = pr_info['author']
118+
# Add event information if available
119+
if 'event' in ci_metadata:
120+
event_info = ci_metadata['event']
121+
122+
# Add event type
123+
if 'event_type' in event_info:
124+
headers['X-Event-Type'] = event_info['event_type']
125+
126+
# Add release tag if available
127+
if 'release_tag' in event_info:
128+
headers['X-Release-Tag'] = event_info['release_tag']
129+
130+
# Add PR information if available
131+
if 'number' in event_info:
132+
headers['X-PR-Number'] = str(event_info['number'])
133+
if 'url' in event_info:
134+
headers['X-PR-URL'] = event_info['url']
135+
if 'source_branch' in event_info:
136+
headers['X-PR-Source-Branch'] = event_info['source_branch']
137+
if 'target_branch' in event_info:
138+
headers['X-PR-Target-Branch'] = event_info['target_branch']
139+
if 'author' in event_info:
140+
headers['X-PR-Author'] = event_info['author']
131141

132142
# Add build information if available
133143
if 'build' in ci_metadata:
@@ -144,14 +154,17 @@ def _get_headers(self):
144154
headers['X-Repository-URL'] = repo_info['url']
145155

146156
# Log CI metadata in debug mode
147-
pr_context = self.config.ci_info.get_pr_context_string()
148-
if pr_context:
149-
logging.debug(f"CI Context: {pr_context}")
157+
event_context = self.config.ci_info.get_event_context_string()
158+
if event_context:
159+
logging.debug(f"CI Context: {event_context}")
150160

151161
# Log the headers being sent (excluding auth token for security)
152162
logged_headers = {k: v for k, v in headers.items() if k != 'Authorization'}
153163
if logged_headers:
154-
logging.debug(f"CI Headers: {logged_headers}")
164+
logging.debug("CI/CD Headers being sent:")
165+
for header_name, header_value in sorted(logged_headers.items()):
166+
if header_name.startswith('X-'):
167+
logging.debug(f" {header_name}: {header_value}")
155168

156169
return headers
157170

@@ -465,6 +478,11 @@ def upload_sbom(self, sbom_file):
465478
self._format_size(file_size))
466479

467480
headers = self._get_headers()
481+
482+
# Log summary of CI headers if present
483+
ci_headers = {k: v for k, v in headers.items() if k.startswith('X-') and k != 'Authorization'}
484+
if ci_headers:
485+
logging.debug(f"Including {len(ci_headers)} CI/CD metadata headers in upload request")
468486

469487
operations = json.dumps({
470488
"query": SBOM_UPLOAD,

0 commit comments

Comments
 (0)