Skip to content

Commit af0acc6

Browse files
committed
Add initial implementation of ClickHouse Cloud IP Whitelist GitHub Action
- Created action to automatically whitelist GitHub Actions runner IP in ClickHouse Cloud with cleanup. - Added TypeScript support with configuration files (.tsconfig.json, .prettierrc.json, .eslint.config.mjs). - Included example workflows for usage and testing. - Implemented logging and error handling for IP management. - Added necessary dependencies and scripts in package.json. - Created README.md with usage instructions and best practices. - Added .gitignore and .prettierignore files for project cleanliness.
0 parents  commit af0acc6

28 files changed

+62530
-0
lines changed

.github/workflows/example.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Example Usage
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
example:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout
11+
uses: actions/checkout@v4
12+
13+
- name: Whitelist Runner IP
14+
id: whitelist
15+
uses: ./
16+
with:
17+
clickhouse-org-id: ${{ secrets.CLICKHOUSE_ORG_ID }}
18+
clickhouse-service-id: ${{ secrets.CLICKHOUSE_SERVICE_ID }}
19+
clickhouse-api-key-id: ${{ secrets.CLICKHOUSE_API_KEY_ID }}
20+
clickhouse-api-key-secret: ${{ secrets.CLICKHOUSE_API_KEY_SECRET }}
21+
22+
- name: Display whitelisted IP
23+
run: |
24+
echo "Runner IP whitelisted: ${{ steps.whitelist.outputs.runner-ip }}"
25+
26+
- name: Simulate ClickHouse operations
27+
run: |
28+
echo "Performing database operations..."
29+
sleep 5
30+
echo "Operations complete!"
31+
32+
# Cleanup happens automatically here
33+
# The IP will be removed from the allowlist
34+

.github/workflows/test.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
16+
- name: Setup Node.js
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: '20'
20+
cache: 'npm'
21+
22+
- name: Install dependencies
23+
run: npm ci
24+
25+
- name: Run format check
26+
run: npm run format-check
27+
28+
- name: Run linter
29+
run: npm run lint
30+
31+
- name: Run tests
32+
run: npm test
33+
34+
- name: Build
35+
run: npm run build
36+
37+
- name: Bundle
38+
run: npm run bundle
39+
40+
- name: Check for uncommitted changes
41+
run: |
42+
if [ -n "$(git status --porcelain)" ]; then
43+
echo "Uncommitted changes found in dist/ directory!"
44+
echo "Please run 'npm run bundle' and commit the changes."
45+
git status --porcelain
46+
exit 1
47+
fi
48+

.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Dependency directories
2+
node_modules/
3+
4+
# TypeScript build output
5+
# NOTE: dist/ is NOT ignored because GitHub Actions needs it!
6+
# The bundled JS files in dist/ must be committed to the repo
7+
*.tsbuildinfo
8+
9+
# Test coverage
10+
coverage/
11+
12+
# IDE
13+
.vscode/
14+
.idea/
15+
*.swp
16+
*.swo
17+
*~
18+
19+
# OS
20+
.DS_Store
21+
Thumbs.db
22+
23+
# Environment variables
24+
.env
25+
.env.local
26+
.env.*.local
27+
28+
# Logs
29+
logs/
30+
*.log
31+
npm-debug.log*
32+
yarn-debug.log*
33+
yarn-error.log*
34+

.prettierignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules/
2+
dist/
3+
coverage/
4+
*.min.js
5+

.prettierrc.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"semi": false,
3+
"trailingComma": "none",
4+
"singleQuote": true,
5+
"printWidth": 80,
6+
"tabWidth": 2,
7+
"arrowParens": "avoid"
8+
}
9+

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Noti-fire Apps Ltd.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# ClickHouse Cloud IP Whitelist Action
2+
3+
A GitHub Action that automatically whitelists your GitHub Actions runner IP address in ClickHouse Cloud, with automatic cleanup after your job completes.
4+
5+
## Features
6+
7+
- 🔐 **Automatic IP Whitelisting**: Adds the current runner's IP to your ClickHouse Cloud service allowlist
8+
- 🧹 **Automatic Cleanup**: Removes the IP from the allowlist when the job completes (even if it fails)
9+
- 🚀 **Zero Configuration**: Just provide your ClickHouse credentials
10+
-**Secure**: Uses ClickHouse Cloud API with proper authentication
11+
12+
## Usage
13+
14+
### Prerequisites
15+
16+
You'll need the following from ClickHouse Cloud:
17+
- Organization ID
18+
- Service ID
19+
- API Key ID
20+
- API Key Secret
21+
22+
### Basic Example
23+
24+
```yaml
25+
name: ClickHouse Migration
26+
27+
on: [push]
28+
29+
jobs:
30+
migrate:
31+
runs-on: ubuntu-latest
32+
steps:
33+
- name: Checkout
34+
uses: actions/checkout@v4
35+
36+
- name: Whitelist Runner IP
37+
uses: your-username/clickhouse-cloud-whitelist-ip@v1
38+
with:
39+
clickhouse-org-id: ${{ secrets.CLICKHOUSE_ORG_ID }}
40+
clickhouse-service-id: ${{ secrets.CLICKHOUSE_SERVICE_ID }}
41+
clickhouse-api-key-id: ${{ secrets.CLICKHOUSE_API_KEY_ID }}
42+
clickhouse-api-key-secret: ${{ secrets.CLICKHOUSE_API_KEY_SECRET }}
43+
44+
- name: Run Database Operations
45+
run: |
46+
# Your ClickHouse operations here
47+
# The runner IP is now whitelisted!
48+
49+
# IP is automatically removed from allowlist after job completes
50+
```
51+
52+
### Using the Output
53+
54+
The action outputs the whitelisted IP address:
55+
56+
```yaml
57+
- name: Whitelist Runner IP
58+
id: whitelist
59+
uses: your-username/clickhouse-cloud-whitelist-ip@v1
60+
with:
61+
clickhouse-org-id: ${{ secrets.CLICKHOUSE_ORG_ID }}
62+
clickhouse-service-id: ${{ secrets.CLICKHOUSE_SERVICE_ID }}
63+
clickhouse-api-key-id: ${{ secrets.CLICKHOUSE_API_KEY_ID }}
64+
clickhouse-api-key-secret: ${{ secrets.CLICKHOUSE_API_KEY_SECRET }}
65+
66+
- name: Show IP
67+
run: echo "Runner IP is ${{ steps.whitelist.outputs.runner-ip }}"
68+
```
69+
70+
## Inputs
71+
72+
| Input | Description | Required |
73+
|-------|-------------|----------|
74+
| `clickhouse-org-id` | ClickHouse Cloud Organization ID | Yes |
75+
| `clickhouse-service-id` | ClickHouse Cloud Service ID | Yes |
76+
| `clickhouse-api-key-id` | ClickHouse Cloud API Key ID | Yes |
77+
| `clickhouse-api-key-secret` | ClickHouse Cloud API Key Secret | Yes |
78+
79+
## Outputs
80+
81+
| Output | Description |
82+
|--------|-------------|
83+
| `runner-ip` | The IP address of the GitHub Actions runner that was whitelisted |
84+
85+
## How It Works
86+
87+
1. **Main Step**:
88+
- Fetches the current runner's public IP address using ipify.org
89+
- Adds the IP (as a /32 CIDR) to your ClickHouse Cloud service's IP allowlist
90+
- Saves the IP and credentials to action state
91+
- Outputs the IP address
92+
93+
2. **Cleanup Step** (runs automatically at job end):
94+
- Retrieves the IP from action state
95+
- Removes the IP from the allowlist
96+
- Runs even if the job fails (using `post-if: always()`)
97+
98+
## Security Best Practices
99+
100+
1. **Store credentials as GitHub Secrets**: Never hardcode your ClickHouse credentials in workflows
101+
2. **Use environment-specific secrets**: Create separate API keys for different environments
102+
3. **Limit API key permissions**: Use the minimum required permissions for your API keys
103+
4. **Monitor access logs**: Regularly check your ClickHouse Cloud access logs
104+
105+
## Troubleshooting
106+
107+
### IP not whitelisted
108+
109+
If you see connection errors:
110+
1. Check that all four credentials are correct
111+
2. Verify your service ID is correct
112+
3. Ensure your API key has permissions to modify IP allowlists
113+
114+
### Cleanup not running
115+
116+
The cleanup step runs automatically using GitHub Actions' `post` lifecycle. It will:
117+
- Run even if previous steps fail
118+
- Only log warnings if cleanup fails (won't fail the job)
119+
120+
## Development
121+
122+
### Building
123+
124+
```bash
125+
# Install dependencies
126+
npm install
127+
128+
# Build TypeScript
129+
npm run build
130+
131+
# Bundle for distribution
132+
npm run bundle
133+
134+
# Run all checks (format, lint, test, bundle)
135+
npm run all
136+
```
137+
138+
### Testing Locally
139+
140+
You can test the action locally using the `@github/local-action` utility:
141+
142+
```bash
143+
# Create a .env file with your credentials (see .env.example)
144+
# Then run:
145+
npx @github/local-action . src/main.ts .env
146+
```
147+
148+
### Project Structure
149+
150+
```
151+
.
152+
├── src/
153+
│ ├── main.ts # Main action (adds IP to allowlist)
154+
│ └── cleanup.ts # Cleanup action (removes IP from allowlist)
155+
├── dist/ # Compiled JavaScript (committed to repo)
156+
├── action.yml # Action metadata
157+
├── package.json # Dependencies and scripts
158+
└── tsconfig.json # TypeScript configuration
159+
```
160+
161+
## Contributing
162+
163+
Contributions are welcome! Please feel free to submit a Pull Request.
164+
165+
## License
166+
167+
MIT
168+
169+
## Acknowledgments
170+
171+
- Built with [actions/toolkit](https://github.com/actions/toolkit)
172+
- IP detection via [ipify.org](https://www.ipify.org/)
173+
- Template from [actions/typescript-action](https://github.com/actions/typescript-action)
174+

__tests__/main.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
describe('ClickHouse Cloud IP Whitelist Action', () => {
2+
it('should be testable', () => {
3+
expect(true).toBe(true)
4+
})
5+
6+
// Add more tests here as needed
7+
// Mock the @actions/core module for unit testing
8+
// Mock fetch calls to test API interactions
9+
})

action.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: 'ClickHouse Cloud IP Whitelist'
2+
description: 'Automatically whitelist GitHub Actions runner IP in ClickHouse Cloud with cleanup'
3+
author: 'Noti-fire Apps Ltd.'
4+
5+
branding:
6+
icon: 'lock'
7+
color: 'yellow'
8+
9+
inputs:
10+
clickhouse-org-id:
11+
description: 'ClickHouse Cloud Organization ID'
12+
required: true
13+
clickhouse-service-id:
14+
description: 'ClickHouse Cloud Service ID'
15+
required: true
16+
clickhouse-api-key-id:
17+
description: 'ClickHouse Cloud API Key ID'
18+
required: true
19+
clickhouse-api-key-secret:
20+
description: 'ClickHouse Cloud API Key Secret'
21+
required: true
22+
23+
outputs:
24+
runner-ip:
25+
description: 'The IP address of the GitHub Actions runner that was whitelisted'
26+
27+
runs:
28+
using: 'node20'
29+
main: 'dist/index.js'
30+
post: 'dist/cleanup.js'
31+
post-if: 'always()'
32+

dist/cleanup.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export {};
2+
//# sourceMappingURL=cleanup.d.ts.map

0 commit comments

Comments
 (0)