Skip to content

Commit 9d88757

Browse files
authored
feat: publish connection results to control plane (#219)
# Description ## Features - Adding the option to set a Bullfrog API token to publish the connection results to the Bullfrog control plane. ## Other changes - Adding support for publishing beta releases and allowing using those releases via the new `_agent-version` action input parameter.
1 parent 02b45b4 commit 9d88757

13 files changed

Lines changed: 1458 additions & 268 deletions

File tree

.github/workflows/bullfrog.yml

Lines changed: 133 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ on:
44
push:
55
branches:
66
- main
7+
- "beta/**"
78

89
pull_request:
10+
types: [opened, synchronize, reopened]
911
branches:
1012
- main
1113

@@ -99,6 +101,135 @@ jobs:
99101
run: |
100102
make test.artifacts
101103
104+
determine-version:
105+
runs-on: ubuntu-22.04
106+
outputs:
107+
version_tag: ${{ steps.version.outputs.tag }}
108+
is_beta: ${{ steps.version.outputs.is_beta }}
109+
steps:
110+
- name: Checkout
111+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
112+
with:
113+
ref: ${{ github.head_ref || github.ref }}
114+
115+
- name: Determine version tag
116+
id: version
117+
run: |
118+
if [[ "${{ github.head_ref }}" != release-please--branches--* ]] && [[ "${{ github.ref }}" != refs/heads/beta/* ]]; then
119+
echo "Not a candidate for a beta release"
120+
echo "is_beta=false" >> $GITHUB_OUTPUT
121+
exit 0
122+
fi
123+
124+
VERSION=$(jq -r '.version' package.json)
125+
126+
# Determine context: beta push or release-please PR
127+
if [[ "${{ github.head_ref }}" == release-please--branches--* ]]; then
128+
# RC release for release-please PR
129+
RC_VERSION=$(jq -r '.[]' .release-please-manifest.json | head -1)
130+
TAG_NAME="v${RC_VERSION}-rc"
131+
elif [[ "${{ github.ref }}" == refs/heads/beta/* ]]; then
132+
# Beta release
133+
BRANCH_NAME="${GITHUB_REF#refs/heads/beta/}"
134+
SANITIZED=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
135+
TAG_NAME="v${VERSION}-beta-${SANITIZED}"
136+
fi
137+
138+
echo "tag=$TAG_NAME" >> $GITHUB_OUTPUT
139+
echo "is_beta=true" >> $GITHUB_OUTPUT
140+
echo "Creating beta release: $TAG_NAME"
141+
142+
create-beta-prerelease:
143+
needs: [determine-version, build, check-artifacts]
144+
if: needs.determine-version.outputs.is_beta == 'true'
145+
runs-on: ubuntu-22.04
146+
timeout-minutes: 5
147+
permissions:
148+
contents: write
149+
steps:
150+
- name: Enable egress filtering
151+
uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3
152+
with:
153+
egress-policy: block
154+
allowed-domains: |
155+
*.github.qkg1.top
156+
uploads.github.com
157+
158+
- name: Checkout
159+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
160+
with:
161+
ref: ${{ github.head_ref || github.ref }}
162+
163+
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
164+
with:
165+
name: build-artifacts
166+
167+
- name: Create or update beta release
168+
env:
169+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
170+
SHA: ${{ github.sha }}
171+
run: |
172+
TAG_NAME="${{ needs.determine-version.outputs.version_tag }}"
173+
IS_BETA="${{ needs.determine-version.outputs.is_beta }}"
174+
175+
# Delete existing release and tag if they exist
176+
gh release delete "$TAG_NAME" --yes || true
177+
git push origin ":refs/tags/$TAG_NAME" || true
178+
179+
RELEASE_TYPE="--prerelease"
180+
TITLE="$TAG_NAME"
181+
NOTES="Automated beta release from branch ${GITHUB_REF#refs/heads/}
182+
183+
**Testing this beta:**
184+
\`\`\`yaml
185+
- uses: bullfrogsec/bullfrog@$SHA
186+
with:
187+
_agent-version: '$TAG_NAME'
188+
egress-policy: block
189+
allowed-domains: example.com
190+
\`\`\`"
191+
192+
# Create release
193+
tar -czf agent.tar.gz agent/agent
194+
gh release create "$TAG_NAME" \
195+
--title "$TITLE" \
196+
--notes "$NOTES" \
197+
--target "$SHA" \
198+
--prerelease \
199+
agent.tar.gz
200+
201+
test-beta-release:
202+
needs: [determine-version, create-beta-prerelease]
203+
if: needs.determine-version.outputs.is_beta == 'true'
204+
runs-on: ubuntu-22.04
205+
timeout-minutes: 5
206+
steps:
207+
- name: Checkout
208+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
209+
with:
210+
ref: ${{ github.head_ref || github.ref }}
211+
212+
- name: Test beta release with action
213+
uses: ./
214+
with:
215+
_agent-version: ${{ needs.determine-version.outputs.version_tag }}
216+
egress-policy: block
217+
allowed-domains: www.google.com
218+
219+
- name: Verify blocking works
220+
run: |
221+
if curl https://www.google.com --max-time 5 --output /dev/null; then
222+
echo "Allowed domain works"
223+
else
224+
echo "Expected curl to allowed domain to succeed"
225+
exit 1
226+
fi
227+
228+
if curl https://www.bing.com --max-time 5 --output /dev/null; then
229+
echo "Block failed - unauthorized domain accessible"
230+
exit 1
231+
fi
232+
102233
test-audit:
103234
needs: build
104235
runs-on: ubuntu-22.04
@@ -188,7 +319,7 @@ jobs:
188319
egress-policy: block
189320

190321
- name: Make HTTP requests
191-
run: |
322+
run: |
192323
source test/make_http_requests.sh
193324
source test/make_docker_pull.sh
194325
@@ -315,7 +446,7 @@ jobs:
315446
make test.types
316447
317448
pre-release:
318-
if: github.ref == 'refs/heads/main'
449+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
319450
runs-on: ubuntu-22.04
320451
permissions:
321452
contents: write
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Cleanup Beta Release
2+
3+
on:
4+
delete:
5+
# This triggers when any ref is deleted
6+
pull_request:
7+
types: [closed]
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: write
13+
14+
jobs:
15+
cleanup-beta:
16+
runs-on: ubuntu-22.04
17+
# Only run for beta branch deletions
18+
if: github.event.ref_type == 'branch' && startsWith(github.event.ref, 'beta/')
19+
timeout-minutes: 2
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
23+
24+
- name: Delete beta release
25+
env:
26+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
run: |
28+
# Get version from package.json on main
29+
VERSION=$(jq -r '.version' package.json)
30+
31+
# Reconstruct the sanitized branch name
32+
BRANCH_NAME="${{ github.event.ref }}"
33+
BRANCH_NAME="${BRANCH_NAME#beta/}"
34+
SANITIZED=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
35+
36+
TAG_NAME="v${VERSION}-beta-${SANITIZED}"
37+
38+
echo "Cleaning up beta release: $TAG_NAME"
39+
40+
# Delete release and tag (ignore errors if they don't exist)
41+
gh release delete "$TAG_NAME" --yes || true
42+
git push origin ":refs/tags/$TAG_NAME" || true
43+
cleanup-rc:
44+
runs-on: ubuntu-22.04
45+
# Only run for release-please PRs
46+
if: ${{ github.event_name == 'pull_request' && startsWith(github.head_ref, 'release-please--branches--') }}
47+
timeout-minutes: 2
48+
steps:
49+
- name: Checkout
50+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
51+
52+
- name: Delete RC release
53+
env:
54+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
55+
run: |
56+
# Extract version from the manifest on main branch
57+
VERSION=$(jq -r '.[]' .release-please-manifest.json | head -1)
58+
TAG_NAME="v${VERSION}-rc"
59+
60+
echo "Cleaning up RC release: $TAG_NAME"
61+
62+
# Delete release and tag (ignore errors if they don't exist)
63+
gh release delete "$TAG_NAME" --yes || true
64+
git push origin ":refs/tags/$TAG_NAME" || true

action.yml

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ inputs:
88
allowed-domains:
99
description: "List of allowed domains for outbound connections."
1010

11+
api-token:
12+
description: "API token for submitting connection results to the Bullfrog control plane. If not provided, results will not be published."
13+
14+
collect-process-info:
15+
description: "Enable this option to collect process information (PID, process name, command line) for network connections. Options: 'true' (default) or 'false'."
16+
type: boolean
17+
default: true
18+
1119
dns-policy:
1220
description: "DNS policy to enforce when egress-policy is set to 'block'. Options: 'allowed-domains-only' (default) or 'any'."
1321
default: "allowed-domains-only"
@@ -22,16 +30,25 @@ inputs:
2230
type: boolean
2331
default: true
2432

25-
collect-process-info:
26-
description: "Enable this option to collect process information (PID, process name, command line) for network connections. Options: 'true' (default) or 'false'."
27-
type: boolean
28-
default: true
29-
3033
_agent-download-base-url:
31-
description: "(Internal) Base URL for fetching the agent binary. This is useful for testing changes in a fork. The URL should end with a slash."
34+
description: "(Internal) Base URL for fetching the agent binary. This is useful for testing changes in a fork."
3235
type: string
3336
default: "https://github.com/bullfrogsec/bullfrog/releases/download/"
3437

38+
_agent-version:
39+
description: "(Internal) Override the agent version to download. Must start with 'v' followed by semver (e.g., 'v0.8.4', 'v0.8.4-beta-feature', 'v1.0.0-rc'). If not specified, uses the version from package.json."
40+
type: string
41+
42+
_control-plane-api-base-url:
43+
description: "(Internal) Base URL for the Bullfrog control plane API. This is useful for testing changes in a fork."
44+
type: string
45+
default: "https://api.bullfrogsec.com/"
46+
47+
_control-plane-webapp-base-url:
48+
description: "(Internal) Base URL for the Bullfrog control plane webapp. This is useful for testing changes in a fork."
49+
type: string
50+
default: "https://app.bullfrogsec.com/"
51+
3552
_log-directory:
3653
description: "(Internal) Directory to store log files."
3754
type: string

0 commit comments

Comments
 (0)