Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,38 @@
TOKEN=
# --------------------------------------------------------------------------- #
# Control D Sync Configuration
#
# Create a copy of this file named .env and fill in your values.
# These variables can also be set as GitHub repository secrets for CI.
# --------------------------------------------------------------------------- #

# Your Control D API token.
# Required.
TOKEN=your_api_token_here

# A comma-separated list of the profile IDs you want to sync.
# Required. Example: PROFILE=abc123def,xyz789ghi
PROFILE=

# --------------------------------------------------------------------------- #
# Profile-specific Folder URLs (Optional)
#
# By default, all profiles use the `DEFAULT_FOLDER_URLS` from `main.py`.
# You can override this for specific profiles using the indexed approach below.
# The index corresponds to the order of profile IDs in your `PROFILE` list.
#
# If a `PROFILE_X_FOLDERS` variable is not set for a profile, it will use
# the default folders.
# --------------------------------------------------------------------------- #

# --- Example ---
# This example assumes: PROFILE=profile_A_id,profile_B_id

# For the first profile ('profile_A_id'), use a custom list of allow-list folders.
# PROFILE_0_FOLDERS="https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/ultimate-known_issues-allow-folder.json","https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/apple-private-relay-allow-folder.json"

# For the second profile ('profile_B_id'), use a custom list of block-list folders.
# PROFILE_1_FOLDERS="https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/badware-hoster-folder.json","https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/native-tracker-amazon-folder.json"

# A third profile in the list would use the default folders, since
# `PROFILE_2_FOLDERS` is not defined.

10 changes: 8 additions & 2 deletions .github/workflows/sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,11 @@ jobs:
- name: Run sync script
env:
TOKEN: ${{ secrets.TOKEN }}
PROFILE: ${{ secrets.PROFILE }}
run: uv run python main.py
# PROFILE and folder lists are non-sensitive configuration values.
# Store them as repository/organization variables and access via vars.
PROFILE: ${{ vars.PROFILE }}
PROFILE_0_FOLDERS: ${{ vars.PROFILE_0_FOLDERS }}
PROFILE_1_FOLDERS: ${{ vars.PROFILE_1_FOLDERS }}
PROFILE_2_FOLDERS: ${{ vars.PROFILE_2_FOLDERS }}
PROFILE_3_FOLDERS: ${{ vars.PROFILE_3_FOLDERS }}
run: uv run python main.py
69 changes: 56 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ A tiny Python script that keeps your Control D Folders in sync with a set of
remote block-lists.

## What it does

1. Downloads the current JSON block-lists.
2. Deletes any existing folders with the same names.
3. Re-creates the folders and pushes all rules in batches.
Expand All @@ -22,6 +23,7 @@ remote block-lists.
1. Log in to your Control D account.
2. Open the Profile you want to sync.
3. Copy the profile ID from the URL.

```
https://controld.com/dashboard/profiles/741861frakbm/filters
^^^^^^^^^^^^
Expand All @@ -30,27 +32,62 @@ https://controld.com/dashboard/profiles/741861frakbm/filters
### Configure the script

1. **Clone & install**

```bash
git clone https://github.com/your-username/ctrld-sync.git
cd ctrld-sync
uv sync
```

2. **Configure secrets**
Create a `.env` file (or set GitHub secrets) with:
2. **Configure secrets & variables**

Create a `.env` file for local runs or configure GitHub for CI. Use Secrets for sensitive values and Repository/Organization Variables for non-sensitive configuration:
- Sensitive (store as GitHub Secrets):

```text
TOKEN=your_control_d_api_token
```

- Non-sensitive (store as GitHub Repository/Organization Variables or in `.env` for local runs):
```text
PROFILE=your_profile_id # or comma-separated list of profile ids (e.g. your_id_1,your_id_2)
PROFILE_0_FOLDERS=https://example.com/folder1.json,https://example.com/folder2.json
PROFILE_1_FOLDERS=https://example.com/folder3.json,https://example.com/folder4.json
```

Notes:
- The workflow reads `${{ secrets.TOKEN }}` for the API token and `${{ vars.PROFILE }}`, `${{ vars.PROFILE_0_FOLDERS }}`, etc. for non-sensitive variables.
- If you prefer all-local configuration, a `.env` file with the same names will work for local runs (but do NOT commit `.env` to the repo).

3. **Configure Folders**

**Option 1: Use default folders for all profiles**
No additional configuration needed. All profiles will use the default folder URLs defined in `main.py`.

**Option 2: Configure different folders for each profile**
Add profile-specific environment variables to your `.env` file using the profile's index (starting from 0). For the first profile ID in your `PROFILE` list, use `PROFILE_0_FOLDERS`, for the second use `PROFILE_1_FOLDERS`, and so on.

Example:

```py
TOKEN=your_control_d_api_token
PROFILE=your_profile_id # or comma-separated list of profile ids (e.g. your_id_1,your_id_2)
# .env
PROFILE=first_profile_id,second_profile_id

# Corresponds to first_profile_id
PROFILE_0_FOLDERS=https://example.com/folder1.json,https://example.com/folder2.json
# Corresponds to second_profile_id
PROFILE_1_FOLDERS=https://example.com/folder3.json,https://example.com/folder4.json
```

3. **Configure Folders**
Edit the `FOLDER_URLS` list in `main.py` to include the URLs of the JSON block-lists you want to sync.
**Option 3: Edit default folders**
Edit the `DEFAULT_FOLDER_URLS` list in `main.py` to change the default folders used when no profile-specific configuration is provided.

> [!NOTE]
> Currently only Folders with one action are supported.
> Either "Block" or "Allow" actions are supported.

4. **Run locally**

```bash
uv run python main.py
```
Expand All @@ -61,12 +98,18 @@ https://controld.com/dashboard/profiles/741861frakbm/filters
### Configure GitHub Actions

1. Fork this repo.
2. Go to the "Actions" Tab and enable actions.
3. Go to the Repo Settings.
4. Under "Secrets and variables > Actions" create the following secrets like above, under "Repository secrets":
- `TOKEN`: your Control D API token
- `PROFILE`: your Control D profile ID(s)
2. Go to the "Actions" tab and enable actions.
3. Go to the repository Settings → "Secrets and variables" → "Actions".
4. Under the "Secrets" tab, add:
- `TOKEN` (your Control D API token)

5. Under the "Variables" tab, add non-sensitive configuration values:
- `PROFILE` (one or more profile IDs, comma-separated)
- `PROFILE_0_FOLDERS`, `PROFILE_1_FOLDERS`, ... (comma-separated folder URLs for each profile index)

6. The workflow will read `TOKEN` from secrets and the others from variables. This prevents accidental leakage of tokens while keeping configuration editable.

## Requirements
- Python 3.12+
- `uv` (for dependency management)

- Python 3.12+
- `uv` (for dependency management)
52 changes: 52 additions & 0 deletions USAGE_EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Example Usage Scenarios

This file shows how to configure your `.env` file or GitHub secrets for different use cases.

## Scenario 1: All profiles use the same default folders

In this setup, all profiles listed in the `PROFILE` variable will be synced with the `DEFAULT_FOLDER_URLS` defined in `main.py`.

```bash
# .env file or GitHub repository secrets
TOKEN=your_token_here
PROFILE=abc123def,xyz789ghi

# No PROFILE_*_FOLDERS variables are set.
# Both profiles will use the default folder URLs.
```

## Scenario 2: All profiles use custom folder lists

In this case, you want to define a specific list of folders for **every** profile. You must provide a `PROFILE_X_FOLDERS` variable for each profile listed in `PROFILE`.

```bash
# .env file or GitHub repository secrets
TOKEN=your_token_here
PROFILE=abc123def,xyz789ghi

# For profile 'abc123def' (index 0)
PROFILE_0_FOLDERS=https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/ultimate-known_issues-allow-folder.json,https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/apple-private-relay-allow-folder.json

# For profile 'xyz789ghi' (index 1)
PROFILE_1_FOLDERS=https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/badware-hoster-folder.json,https://raw.githubusercontent.com/hagezi/dns-blocklists/main/controld/native-tracker-amazon-folder.json
```

## Scenario 3: Some profiles use custom lists, others use defaults

This is a hybrid approach. You can define custom folder lists for specific profiles, while letting any others that are not explicitly defined fall back to the `DEFAULT_FOLDER_URLS`.

```bash
# .env file or GitHub repository secrets
TOKEN=your_token_here
PROFILE=abc123def,xyz789ghi,jkl456mno

# For profile 'abc123def' (index 0)
PROFILE_0_FOLDERS=https://example.com/custom1.json,https://example.com/custom2.json

# For profile 'xyz789ghi' (index 1)
PROFILE_1_FOLDERS=https://example.com/custom3.json

# Profile 'jkl456mno' (index 2) has no PROFILE_2_FOLDERS variable,
# so it will fall back to using the default folder URLs.
```

Loading