text:
# Running the Blocklists

1. Setup Fediblockhole
```bash
python3 -m pip install fediblockhole
```

2. Clone this Repo
```bash
git clone https://codeberg.org/oliphant/blocklists.git /opt/fediblockhole
# optional: create folders for local scripts and secret config
# mkdir /opt/fediblockhole/local && mkdir /opt/fediblockhole/secretconfig
```

3. Execute
`/opt/fediblockhole/fedisync.sh`

That's it. Blocklists will be written to the `blocklists` folder.

You can use `local` and `secretconfig` as subfolders that aren't tracked by git to create your own versions of these scripts and config.

4. Optional
`./fedisync-push.sh`
This will sync up a specified blocklist (any blocklist you want) to a specified destination. This is not required to generate blocklists.

For more information on how to configure the push file, or a greater explanation of the fundamentals of this process, see [How to Sync up Blocklist Changes From Trusted Sources](https://writer.oliphant.social/oliphant/how-to-sync-up-blocklist-changes-from-trusted-sources).

---

## Configuration

The list of blocklist sources can be found in the [/config/pull.conf.toml](/oliphant/blocklists/src/branch/main/config/pull.conf.toml).

These initial sources are pulled down, with each of them being saved as an intermediate file.

> Note: If you want to include the public_description, modify the [/config/pull.all.conf.toml](/oliphant/blocklists/src/branch/main/config/pull.all.conf.toml) file.

The `fedisync.sh` script renames each of these source lists to a more friendly name (like mastodon.social.csv)

The remaining steps are performed on these sourcefiles, not pulled from urls.

If you customize the list of sources in `pull.conf.toml` or `pull.all.conf.toml` you should also update them in the various `config/*.conf.toml` files as needed.

You will likely also need to customize the `fedisync.sh` to your needs as well if you make these changes.

## Generate files with descriptions

Edit the `fedisync.sh` file, and where you see as follows:

```
PULLCONFIG="/opt/fediblockhole/config/pull.conf.toml" # default, pull sources WITHOUT public_description
#PULLCONFIG="/opt/fediblockhole/config/pull.all.conf.toml" # pull down all sources WITH public_description
```

Comment out the first line and uncomment the second. Then run `fedisync.sh` as normal. The resulting files will have public_comment populated.

Alternately, edit `pull.conf.toml` as follows to uncomment the 'public_comment' row:

```
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']
```

## Pushing to Your Own Server
If you want to push these blocks to your own server, that's an option, too.

An example of this is in `fedisync-push.sh`. You can copy it to `/local/fedisync-push.sh` and modify it. If you want to push to a git repo, that references `fedisync-git.sh`. If you want to automatically sync a merged or list to your own server, the `fedisync-example-server.sh` script should be modified for your use.

You will need a [very permissive API key](https://writer.oliphant.social/oliphant/how-to-sync-up-blocklist-changes-from-trusted-sources#generate-an-admin-api-token) created for your server to allow the push script to talk to it.

By default, this is configured to downgrade any suspensions to silence while there are follow relationships on your server against a given block.

Note that `fedisync-push.sh` won't push to any servers at all until you update the API key and the configuration for it.

repo_name: sgrigson/oliphant

repo_language: Shell

mime_type: text/x-objective-c


text:
#!/bin/bash
set -e
# generate files
#exec > >(tee /opt/fediblockhole/logs/fedisync.log) 2>&1
exec 2> >(tee /opt/fediblockhole/logs/fedisync-git.log)
echo "Pushing up git changes..."

cd /opt/fediblockhole

date=$(date '+%Y-%m-%d %H:%M:%S')

GIT=`which git`
${GIT} add --all
${GIT} commit -m "automated commit on $date"
${GIT} push
#${GIT} pushall

echo "Push complete."


text:
#!/bin/bash
set -e
# generate files
exec > >(tee /opt/fediblockhole/logs/fedisync-production.log) 2>&1

# push to github and codeberg
# note: copy your own version to /fediblockhole/local
/opt/fediblockhole/fedisync-git.sh

# push to remote servers
/opt/fediblockhole/fedisync-example-server.sh


text:
#!/bin/bash
set -e
# export to production servers

SYNC=`which fediblock-sync`

# use secretconfig subfolder
${SYNC} -c /opt/fediblockhole/config/example-server-export.conf.toml


text:
#!/bin/bash
set -e

# generate files
#exec > >(tee /opt/fediblockhole/logs/fedisync.log) 2>&1
exec 2> >(tee /opt/fediblockhole/logs/fedisync.log)
echo "Pulling down all blocklist sources..."

cd /opt/fediblockhole

GIT=`which git`
${GIT} fetch
#${GIT} fetchall

PULLCONFIG="/opt/fediblockhole/config/pull.conf.toml" # default, pull sources WITHOUT public_description
#PULLCONFIG="/opt/fediblockhole/config/pull.all.conf.toml" # pull down all sources WITH public_description

SYNC=`which fediblock-sync`
${SYNC} -c $PULLCONFIG # pull down all files, create max list

# rename and remove intermediate files
rm -f /opt/fediblockhole/blocklists/file:---opt-fediblockhole-blocklists-__allowlist.csv.csv
mv /opt/fediblockhole/blocklists/https:--seirdy.one-pb-tier0.csv.csv /opt/fediblockhole/blocklists/tier0.csv
mv /opt/fediblockhole/blocklists/https:--seirdy.one-pb-pleroma.envs.net.csv.csv /opt/fediblockhole/blocklists/pleroma.envs.net.csv
mv /opt/fediblockhole/blocklists/https:--raw.githubusercontent.com-gardenfence-blocklist-main-gardenfence-fediblocksync.csv.csv /opt/fediblockhole/blocklists/gardenfence.csv
mv /opt/fediblockhole/blocklists/https:--artisan.chat-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/artisan.chat.csv
mv /opt/fediblockhole/blocklists/https:--mastodon.art-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/mastodon.art.csv
mv /opt/fediblockhole/blocklists/https:--mastodon.online-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/mastodon.online.csv
mv /opt/fediblockhole/blocklists/https:--mastodon.social-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/mastodon.social.csv
mv /opt/fediblockhole/blocklists/https:--rage.love-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/rage.love.csv
mv /opt/fediblockhole/blocklists/https:--sunny.garden-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/sunny.garden.csv
mv /opt/fediblockhole/blocklists/https:--toot.wales-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/toot.wales.csv
mv /opt/fediblockhole/blocklists/https:--union.place-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/union.place.csv
mv /opt/fediblockhole/blocklists/https:--solarpunk.moe-api-v1-instance-domain_blocks.csv /opt/fediblockhole/blocklists/solarpunk.moe.csv

# destroy the 'max' list
rm -f /opt/fediblockhole/blocklists/_unified_max_blocklist.csv

# create fedi council tier0 file and 100% file
${SYNC} -c /opt/fediblockhole/config/council.tier0.conf.toml && \
${SYNC} -c /opt/fediblockhole/config/100.percent.conf.toml

# create unified tier0 file
${SYNC} -c /opt/fediblockhole/config/tier0.conf.toml

# create missing from mastodon.social blocklist file, and the inverse file
#${SYNC} -c /opt/fediblockhole/config/ms-noblock.conf.toml && \
#${SYNC} -c /opt/fediblockhole/config/ms-we-block.conf.toml

# create intermediate working tier files
${SYNC} -c /opt/fediblockhole/config/tier1-threshold.conf.toml -m min && \
${SYNC} -c /opt/fediblockhole/config/tier2-threshold.conf.toml -m min && \
${SYNC} -c /opt/fediblockhole/config/tier3-threshold.conf.toml -m min

# merge in associated tier file with tier0 blocks
${SYNC} -c /opt/fediblockhole/config/tier1.conf.toml -m min && \
${SYNC} -c /opt/fediblockhole/config/tier2.conf.toml -m min && \
${SYNC} -c /opt/fediblockhole/config/tier3.conf.toml -m min && \
cp /opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv /opt/fediblockhole/blocklists/_unified_min_blocklist.csv

# cleanup working tier files
rm -f /opt/fediblockhole/blocklists/_working_*.csv

# copy all files to mastodon subfolder
cp /opt/fediblockhole/blocklists/*.csv /opt/fediblockhole/blocklists/mastodon/ && \
cp /opt/fediblockhole/blocklists/README.md /opt/fediblockhole/blocklists/mastodon/README.md

echo "Creating mastodon versions of files..."

# convert files to Mastodon header
cd /opt/fediblockhole/blocklists/mastodon

rm -f __allowlist.csv

# replace first line with mastodon-format header row
headerrow="#domain,#severity,#reject_media,#reject_reports,#public_comment,#obfuscate"
for file in *.csv; do
    sed -i "1s/.*/$headerrow/" $file
    # replace bad line terminators
    sed -i "s/\r//g" $file
    # lowercase file to fix booleans
    sed -i "s/\(.*\)/\L\1/" $file
done

echo "Pull complete."


text:
# Oliphant.Social Shared Blocklist Files

See `RUNNING.md` for more information on running the scripts in this repo to generate these blocklists yourself, to modify the sources, or push the blocks to a server you control. You are encouraged to fork this repo, create your own versions of these scripts, and push up your own blocklist files, or use this simply to keep a server in sync with blocklist updates.

This folder contains scripts to generate the blocklist files. See the `blocklists` folder for blocklist files.

For more information, please check out some blog entries:

* [The Blocklist Algorithm](https://writer.oliphant.social/oliphant/the-blocklist-algorithm)
How the various lists were built, and the algorithms behind Tier 0-3.
* [How to Sync Up Blocklist Changes From Trusted Sources](https://writer.oliphant.social/oliphant/how-to-sync-up-blocklist-changes-from-trusted-sources)
A step-by-step tutorial on how to install FediBlockHole yourself and start pulling down blocklists and applying them to your server.
* [Blocklists](https://writer.oliphant.social/oliphant/blocklists)
Several thousand words about blocklists and defederation.

Blocklists are dual hosted at:

* https://github.com/sgrigson/oliphant
* https://codeberg.org/oliphant/oliphant

If you're pulling down the repo instead of downloading files directly, you can use `git remote set-url` to switch locations if needed.

---
## The Tier Consensus System

Tiers will reflect blocklist size, with higher tiers having larger blocklists. This is purely mathematical, and pulls from trusted sources to generate this list based on common agreement.

You are encouraged to use these lists if you find them useful, or you can rely more on an individual trusted source in the list and reference their blocklist instead.

The advantage of a tier merge is that it acts like a second (or third) opinion. Most of these blocks use a *min* merge strategy, meaning that a single source choosing 'silence' over 'suspend' will force that domain to be silenced instead of suspended.

All tiers are based on mathematical consensus, and at least 2 sources must agree for a source to be on any list.

* Tier 0 - Requires 60-80% consensus on blocks to appear on this list.
* Tier 1 - Requires 50% consensus to appear on this list
* Tier 2 - Requires 33% consensus
* Tier 3 - Requires 2 sites (moved and seconded) to appear on the list

Note that unless the list specifies otherwise, blocks from a lower tier are always included. That means Tier0 blocks are in every unified (merged) list.

## What's The Purpose Here?

We see issues from the same servers, over and over again. No one has ever coordinated this data before in such a way, and it's coordination (which began with the fediblock hashtag) which has helped create a better, safer space already. There is more work to be done here.

This is our best-guess of the kinds of blocks you might need to keep the fedi weird *and* safe. Note: There is clearly no universal agreement here, even among the server admins who agreed to participate. This is herding cats.

So we give you as much information as possible, from as many admins who agreed to participate and let you pick a tier list that suits your level of "blockingness", or an individual source list that most closely matches the identity and needs of your server community.

## Where's the Receipts?

Not here. There is no reason to get into any fights about what is essentially a point-in-time *status report*. These are easily importable blocks that can be reviewed and opted out of individually. In a searchable format with a static URL they can also be used to drive other consensus-based blocklist projects and become a Trusted Source for others in syncing up and maintaining their blocklists.

The receipts, in other words, are federated. They just aren't here. You'll have to search for them, but the [Bad Space](https://thebad.space/about) is coming online and should eventually have all the receipts for public availability.

## How Often are the Lists Updated?

On the hour, every hour, so long as there have been changes from one of the blocklist sources.

## Fair Use and Context for Blocklists

Blocklists are provided in the public interest and for server admins who maintain a legitimate interest in performing the normal daily operation of their server, which includes [active moderation](https://joinmastodon.org/covenant), review of potential sources of harm or even just places viewed with caution due to unsafe or lax moderation practices.

Everyone argues about where to draw this line. That's the whole point of providing multiple sources here (and I'll provide others if they opt in). Ideally, you will pull in a blocklist from other sources you trust. That may be one of these sources, a merged version of the different lists, or you may use it for reference.

There are several non-standard use cases as well:

* “Hmm...I’m on the fence about this domain. Oh look, it’s in this blocklist too; let me ask them about it.”
* “I’ve imported a large blocklist, but I’m unsure about some entries. They’re tier-3 entries but not tier-2  or tier-1; I think I’ll downgrade them from suspend to something less severe.”
* “Someone sent me a follow-request, and I see they’re a new user from a tier-zero domain; I think I’ll decline.”

Ultimately, how a list is used is up to you.

It's assumed you're a rational person and can deal with what we hope are small disagreements with some of the entries on the list.

It's also assumed you're capable of *not importing certain lines* or just editing the file as necessary. Use it as a basis to create your shared blocklist file.

Or... decide you do not want to use it at all.

## Trusted Sources

The [trusted sources for this project](https://writer.oliphant.social/oliphant/the-blocklist-algorithm#fedi-council-trusted-source-files) have been willing to provide their blocklists publicly. You are encouraged to run the blocklists yourself. See `RUNNING.md` for details. You can change the trusted sources, or pull in descriptions as well.

It should be noted that these are my trusted sources, and they are also the ones willing to come forward publicly and be a member of this project. They need not be trusted by you, and you are encouraged to use whatever sources you like, and include descriptions in your own blockfiles. If you are going to post your fork of these lists publicly and include changes to the blocklists with new sources, it would be a courtesy to them to get their permission as well.


text:
# Blocklist Index

**NOTE:** Mastodon.social and mastodon.online blocklists are provided for download as a sort of 'control group' for comparison, but are not weighted with other blocklists into the tiered blocklists.

* `100.percent.csv` - Blocks that are on 100% of all blocklists for all sources.
* `__allowlist.csv` - The 'safelist' to ensure that accidental defederations don't happen. Nothing in this list will appear in a unified blocklist.
* `_unified_tier0_blocklist.csv` - Combines blocks from all T0 sources (Seirdy, Gardenfence, Council) into a unified Tier 0 file.
* `_unified_tier1_blocklist.csv` - Requires 50% consensus to appear on this list. Includes Tier 0.
* `_unified_tier2_blocklist.csv` - Requires 33% consensus to appear on this list. Includes Tier 0 and Tier 1.
* `_unified_tier3_blocklist.csv` - Requires 2 sources to agree for it to appear on this list. Includes Tier 0, 1, and 2.
* `tier0.csv` - The original Tier0 file. Algorithmic *and* curated. See Seirdy's [Fediverse Blocklists](https://seirdy.one/posts/2023/05/02/fediverse-blocklists/) for notes about the process behind creating it.
* `gardenfence.csv` - A mirror of the [Gardenfence](https://gardenfence.github.io/) Tier 0 file.
* `tier0-council.csv` - Requires 80% agreement on blocks from trusted sources.
* `birdsite.csv` - All the Birdsite Live Blocks. This file is provided separately as a convenience.
* `dni.csv` - Do Not Interact (DNI). Badly-moderated servers that have returned hits for illegal content. Merged into all unified T0-T3 lists.
* `_unified_min_blocklist.csv` - [Deprecated] Identical to the `_unified_tier0_blocklist.csv`.
* *Other Files* - Other files listed here are individual trusted sources who provided data for the blocklist.

**Subfolders:**

* `mastodon` - identical blocklist data, but with proper mastodon headers in format `#domain,#severity...` etc.
* `other` - These aren't blocklists, but reports.


text:
## All the T0 stuff m.s. blocks that we don't at T0

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/mastodon.social.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/other/council-missing-mastodon.social.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Pull Trusted Sources - Retrieve all sources and write MAX merge file

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = [
  { domain = 'mastodon.social' },
  { domain = 'mastodon.online' },
  { domain = 'union.place' },
  { domain = 'sunny.garden' },
  { domain = 'toot.wales' },
  { domain = 'mastodon.art'},
  { domain = 'rage.love' },
  { domain = 'artisan.chat'},
  { domain = 'solarpunk.moe'},
]

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
 # tier 0
 { url = 'https://seirdy.one/pb/tier0.csv', format = 'csv'},
 { url = 'https://raw.githubusercontent.com/gardenfence/blocklist/main/gardenfence-fediblocksync.csv', format = 'csv'},
 # other sources
 { url = 'https://seirdy.one/pb/pleroma.envs.net.csv', format = 'csv' },
]

# assumes a git pull will proceed this check and bring down the most recent allowlist
allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = true

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_unified_max_blocklist.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'max'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
import_fields = ['reject_media', 'reject_reports', 'obfuscate']
#import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Tier2

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  # bring in tier0
  { url = 'file:///opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
  # tier 2
  { url = 'file:///opt/fediblockhole/blocklists/_working_tier2.csv', format = 'csv' },
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_unified_tier2_blocklist.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## All the T0 stuff m.s. doesn't block

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/mastodon.social.csv', format = 'csv' },
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/other/missing-tier0-mastodon.social.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## MAX Unified File

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/union.place.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/sunny.garden.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/mastodon.art.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/artisan.chat.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/toot.wales.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/rage.love.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/pleroma.envs.net.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/solarpunk.moe.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_working_tier1.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Optional threshold-based merging.
# Only merge in domain blocks if the domain is mentioned in
# at least `threshold` blocklists.
# `merge_thresold` is an integer, with a default value of 0.
# The `merge_threshold_type` can be `count` or `pct`.
# If `count` type is selected, the threshold is reached when the domain
# is mentioned in at least `merge_threshold` blocklists. The default value
# of 0 means that every block in every list will be merged in.
# If `pct` type is selected, `merge_threshold` is interpreted as a percentage,
# i.e. if `merge_threshold` = 20, blocks will only be merged in if the domain
# is present in at least 20% of blocklists.
# Percentage calculated as number_of_mentions / total_number_of_blocklists.
# The percentage method is more flexibile, but also more complicated, so take care
# when using it.
#
merge_threshold_type = 'pct'
merge_threshold = 50

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Tier1

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  # bring in tier0
  { url = 'file:///opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
  # tier 1
  { url = 'file:///opt/fediblockhole/blocklists/_working_tier1.csv', format = 'csv' },
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_unified_tier1_blocklist.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Fedi Council Tier 0 File

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
 { url = 'file:///opt/fediblockhole/blocklists/pleroma.envs.net.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/union.place.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/sunny.garden.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/toot.wales.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/mastodon.art.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/rage.love.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/artisan.chat.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/solarpunk.moe.csv', format = 'csv' },
]

# assumes a git pull will proceed this check and bring down the most recent allowlist
allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/tier0-council.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

merge_threshold_type = 'pct'
merge_threshold = 80

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## TIER0 File

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/tier0.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/gardenfence.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/tier0-council.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/dni.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'max'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Example Server Export File

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  { domain = 'server.example.com', token = '<your server token>', max_followed_severity = 'silence'},
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/exports/example_server_blocklist.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = false

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Pull Trusted Sources - With public_description

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = [
  { domain = 'mastodon.social' },
  { domain = 'mastodon.online' },
  { domain = 'union.place' },
  { domain = 'sunny.garden' },
  { domain = 'toot.wales' },
  { domain = 'mastodon.art'},
  { domain = 'rage.love' },
  { domain = 'artisan.chat'},
  { domain = 'solarpunk.moe'},
]

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
 # tier 0
 { url = 'https://seirdy.one/pb/tier0.csv', format = 'csv'},
 { url = 'https://raw.githubusercontent.com/gardenfence/blocklist/main/gardenfence-fediblocksync.csv', format = 'csv'},
 # other sources
 { url = 'https://seirdy.one/pb/pleroma.envs.net.csv', format = 'csv' },
]

# assumes a git pull will proceed this check and bring down the most recent allowlist
allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = true

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_unified_max_blocklist.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'max'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Fedi Council 100% file

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
 { url = 'file:///opt/fediblockhole/blocklists/pleroma.envs.net.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/union.place.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/sunny.garden.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/toot.wales.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/mastodon.art.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/rage.love.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/artisan.chat.csv', format = 'csv' },
 { url = 'file:///opt/fediblockhole/blocklists/solarpunk.moe.csv', format = 'csv' },
]

# assumes a git pull will proceed this check and bring down the most recent allowlist
allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/100.percent.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

merge_threshold_type = 'pct'
merge_threshold = 100

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Tier 2 threshold file

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/union.place.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/sunny.garden.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/mastodon.art.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/artisan.chat.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/toot.wales.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/rage.love.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/pleroma.envs.net.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/solarpunk.moe.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_working_tier2.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Optional threshold-based merging.
# Only merge in domain blocks if the domain is mentioned in
# at least `threshold` blocklists.
# `merge_thresold` is an integer, with a default value of 0.
# The `merge_threshold_type` can be `count` or `pct`.
# If `count` type is selected, the threshold is reached when the domain
# is mentioned in at least `merge_threshold` blocklists. The default value
# of 0 means that every block in every list will be merged in.
# If `pct` type is selected, `merge_threshold` is interpreted as a percentage,
# i.e. if `merge_threshold` = 20, blocks will only be merged in if the domain
# is present in at least 20% of blocklists.
# Percentage calculated as number_of_mentions / total_number_of_blocklists.
# The percentage method is more flexibile, but also more complicated, so take care
# when using it.
#
merge_threshold_type = 'pct'
merge_threshold = 33

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Tier3

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  # bring in tier0
  { url = 'file:///opt/fediblockhole/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
  # tier 0
  { url = 'file:///opt/fediblockhole/blocklists/_working_tier3.csv', format = 'csv' },
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_unified_tier3_blocklist.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
## Tier 3 Threshold file

# List of instances to read blocklists from.
# If the instance makes its blocklist public, no authorization token is needed.
#   Otherwise, `token` is a Bearer token authorised to read domain_blocks.
# If `admin` = True, use the more detailed admin API, which requires a token with a
#   higher level of authorization.
# If `import_fields` are provided, only import these fields from the instance.
#   Overrides the global `import_fields` setting.
blocklist_instance_sources = []

# List of URLs to read csv blocklists from
# Format tells the parser which format to use when parsing the blocklist
# max_severity tells the parser to override any severities that are higher than this value
# import_fields tells the parser to only import that set of fields from a specific source
blocklist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/union.place.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/sunny.garden.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/mastodon.art.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/artisan.chat.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/toot.wales.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/rage.love.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/pleroma.envs.net.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/solarpunk.moe.csv', format = 'csv' },
]

# List of instances to write blocklist to
blocklist_instance_destinations = [
  # { domain = 'eigenmagic.net', token = '<read_write_token>', max_followed_severity = 'silence'},
]

allowlist_url_sources = [
  { url = 'file:///opt/fediblockhole/blocklists/__allowlist.csv', format = 'csv' },
  { url = 'file:///opt/fediblockhole/blocklists/birdsite.csv', format = 'csv' },
]

## Store a local copy of the remote blocklists after we fetch them
save_intermediate = false

## Directory to store the local blocklist copies
savedir = '/opt/fediblockhole/blocklists/'

## File to save the fully merged blocklist into
blocklist_savefile = '/opt/fediblockhole/blocklists/_working_tier3.csv'

## Don't push blocklist to instances, even if they're defined above
no_push_instance = true

## Don't fetch blocklists from URLs, even if they're defined above
# no_fetch_url = false

## Don't fetch blocklists from instances, even if they're defined above
# no_fetch_instance = false

## Set the mergeplan to use when dealing with overlaps between blocklists
# The default 'max' mergeplan will use the harshest severity block found for a domain.
# The 'min' mergeplan will use the lightest severity block found for a domain.
mergeplan = 'min'

## Optional threshold-based merging.
# Only merge in domain blocks if the domain is mentioned in
# at least `threshold` blocklists.
# `merge_thresold` is an integer, with a default value of 0.
# The `merge_threshold_type` can be `count` or `pct`.
# If `count` type is selected, the threshold is reached when the domain
# is mentioned in at least `merge_threshold` blocklists. The default value
# of 0 means that every block in every list will be merged in.
# If `pct` type is selected, `merge_threshold` is interpreted as a percentage,
# i.e. if `merge_threshold` = 20, blocks will only be merged in if the domain
# is present in at least 20% of blocklists.
# Percentage calculated as number_of_mentions / total_number_of_blocklists.
# The percentage method is more flexibile, but also more complicated, so take care
# when using it.
#
merge_threshold_type = 'count'
merge_threshold = 2

## Set which fields we import
## 'domain' and 'severity' are always imported, these are additional
##
#import_fields = ['reject_media', 'reject_reports', 'obfuscate']
import_fields = ['public_comment', 'reject_media', 'reject_reports', 'obfuscate']

## Set which fields we export
## 'domain' and 'severity' are always exported, these are additional
##
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'obfuscate']


text:
CC0 1.0 Universal

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.

For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.

Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;

ii. moral rights retained by the original author(s) and/or performer(s);

iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;

iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;

v. rights protecting the extraction, dissemination, use and reuse of data in a Work;

vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and

vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.

Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.

Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.

Limitations and Disclaimers.

a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.

b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.

c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.

d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.

For more information, please see http://creativecommons.org/publicdomain/zero/1.0

repo_name: public-transport/transport-apis

mime_type: text/plain


text:
# list of transport APIs

**This is a machine-readable list of (public) transport API endpoints**, with details about who operates them, the protocol used & authentication details.

## Format

### Overall Structure

There is a single JSON file per API endpoint. It must contain the following
properties:

* `name`: endpoint name
* `type`: endpoint protocol description (see below)
* `supportedLanguages`: list of supported languages (see below)
* `coverage`: the geographic area this endpoint provides results for (see below)
* `options`: protocol-specific options (not specified here)

### Endpoint Protocol

```js
{
    "type": {
        "hafasMgate": true
    }
}
```

Known protocols:
* `efa`
* `hafasMgate`
* `hafasQuery`
* `navitia`
* `otpGraphQl`
* `otpRest`
* `trias`
* `motis`

### Supported Languages

```js
{
    "supportedLanguages": [
        "en",
        "de",
        "fr",
        "es"
    ]
}
```

A list of ISO-639-1 language codes describing the languages supported by the
endpoint.

### Timezone Information

```js
{
    "timezone": "Europe/Berlin"
}
```

For endpoints that assume times in requests to be in a specific local timezone, the `timezone` field
should contain the [IANA timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) of the
expected timezone. This timezone can also be applied by clients to times in results returned by the endpoint,
particularly when the results are lacking explicit timezone (offset) information.

### Coverage Information

Describes the geographic area this endpoint provides results for.

```js
{
    "coverage": {
        "realtimeCoverage": { /* ... */ },
        "regularCoverage": { /* ... */ },
        "anyCoverage": { /* ... */ }
    }
}
```

There's three coverage categories:
* `realtimeCoverage`: In this area the endpoint provides accurate and highly detailed information.
  This is typically where the operator can rely on live data about their own vehicles.

* `regularCoverage`: In this area reasonably complete data is available, but e.g. realtime data from other operators is missing or inaccurate quite often.

* `anyCoverage`: In this area only incomplete and/or shallow data is available. This is commonly the case in areas outside the operating area,
e.g. long-distance trains & buses but not local modes of transport, or planned data but not realtime data.
You could say that this is the extent to which, in a region, the API provides any data.

At least one coverage category must be provided.

```js
{
    "area": { /* GeoJSON polygon or MultiPolygon */ },
    "region": [ /* ISO-3166-1/2 codes */ ]
}
```

The following properties are defined for each coverage category:
* `area`: a GeoJSON Polygon or MultiPolygon defining the geographic area. This can be reasonably coarse; meter-precision is neither necessary nor practically meaningful.
* `region`: an array of ISO-3166-1 alpha 2 country codes, or ISO-3166-2 region codes covered.

Both fields should be provided.

### Attribution Information

The `attribution` property specifies licensing information for an endpoint.

#### Open Data

If an endpoint provides results under an Open Data license, `attribution`
generally follows the [Data Packages format](https://dataprotocols.org/data-packages/):

```js
{
    "attribution": {
        "name": "© Helsinki Region Transport",
        "license": "CC-BY-4.0",
        "homepage": "https://www.hsl.fi/"
    }
}
```

Properties:
* `license`: An [Open Definition license ID](https://licenses.opendefinition.org/) or an [SPDX license id](https://spdx.org/licenses/).
* `name` and `homepage`: The entity to attribute for licenses requiring this.

name and license are mandatory, homepage is optional.

For endpoints aggregating data under various Open Data licenses, the situation can be
more complex than this though, making it impossible to specify a single license. This
can be expressed using the `mixedLicenses` property:

```js
{
    "attribution": {
        "name": "© navitia.io",
        "homepage": "https://www.navitia.io/",
        "mixedLicenses": true
    }
}
```

If `mixedLicenses` is set to `true`, the license details are provided in some
other form. This can be for example via the `homepage` property, or as part
of the endpoint responses themselves.

#### Proprietary

If an endpoint is known to be proprietary, `attribution` can be used to specify
this as well:

```js
{
    "attribution": {
        "isProprietary": true
    }
}
```

### Protocol Specific Options

#### Hafas mgate.exe

```js
"options": {
    "auth": {
        "aid": "...",
        ...
    },
    "checksumSalt": "<hex value>",
    "client": {
        "id": "...",
        "type": "...",
        ...
    },
    "ext": "...",
    "micMacSalt": "<hex value>",
    "version": "1.27",
    "products": [
        {
            id: 'subway',
            name: 'U-Bahn'
            bitmasks: [1]
        },
        {
            id: 'suburban',
            bitmasks: [2],
            name: 'S-Bahn'
        },
        ...
    ]
}
```

The following properties are defined:
* `auth`: JSON object with static authentication information as passed verbatim in Hafas requests. Mandatory for all known endpoints.
* `checksumSalt`: A string containing a hexadecimal representation of the salt to hash the request body with. Mandatory for endpoints using this authentication mechanism.
* `client`: JSON object with static client information passed verbatim in Hafas requests.
* `ext`: String with the extension version (?) included in Hafas request.
* `micMacSalt`: A string containing a hexadecimal representation the salt to hash the hashed request body with. Mandatory for endpoints using this authentication mechanism.
* `version`: String containing the requested Hafas API version (?), mandatory for all known endpoints.
* `products`: Information about the Hafas product bitmask values and the corresponding product metadata (see below).

Product metadata consists of the following information:
* `id`: An URL-safe slug-ified version of the name, for machine use.
* `name`: A human-readable label for the product, as used by the operator.
* `bitmasks`: An array of integer values of bit values used by Hafas for this product.

#### Hafas query.exe

```js
"options": {
    "endpoint": "https://.../",
    "products": [
        {
            id: 'subway',
            name: 'U-Bahn'
            bitmasks: [1]
        },
        {
            id: 'suburban',
            bitmasks: [2],
            name: 'S-Bahn'
        },
        ...
    ]
}
```

The following properties are defined:
* `endpoint`: The base URL containing the various endpoints (`query.exe`, `stboard.exe`, etc).
* `products`: Hafas product metadata, see the Hafas mgate.exe variant above for the format details.

#### EFA

``` js
"options": {
    "endpoint": "https://...",
    "supportedOutputFormats": [ "XML", "JSON" ],
    "xmlOutputFormat": "full",
    "mId": "...",
    "stopfinderRequestCommand": "XSLT_STOPFINDER_REQUEST",
    "dmRequestCommand": "XSLT_DM_REQUEST",
    "tripRequestCommand": "XSLT_TRIP_REQUEST2"
}
```

The following properties are defined:
* `endpoint`: Base URL for EFA requests, mandatory.
* `supportedOutputFormats`: an array of strings containing valid arguments to the outputFormat parameter of an EFA query (`XML` and/or `JSON`).
* `xmlOutputFormat`: a string specifying the XML output format variant, either `full` or `compact`.
* `mId`: Value of the `mId` query argument. Omitted if not set.
* `stopfinderRequestCommand`: The command used for stop finder requests (default: `XML_STOPFINDER_REQUEST`).
* `dmRequestCommand`: The command used for departure monitor requests (default: `XML_DM_REQUEST`).
* `tripRequestCommand`: The command used for trip requests (default: `XML_TRIP_REQUEST2`).

#### Open Trip Planner with GraphQL

``` js
"options": {
    "endpoint": "https://...",
    "apiVersion": "otp2"
}
```

The following properties are defined:
* `endpoint`: Base URL for the API, without e.g. the `index/graphql` suffix.
* `apiVersion`: One of `otp1`, `otp2` or `entur`.

#### TRIAS

The following properties are defined:
* `endpoint`: Base URL for the API
* `isTestingEndpoint`: Whether the endpoint is explicitly meant for testing purposes
* `triasVersion`: Highest [TRIAS version](https://github.com/VDVde/TRIAS/releases) supported by the API
* `requestContentType`: [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) e.g. `text/xml`
* `requiresSignUp`: Whether one needs to sign up to obtain an API key.
* `requiresContract` Whether one needs to sign a contract to use the API.
* `authorizationMethod`: One of `Authorization-Header`, `RequestorRef`
* `providedServices`: array of supported services as listed [in the EKAP documentation](https://www.vdv.de/431-2sdes-v-1-3.pdfx#page=51)
* `requestLimitPolicy`: request-policy in the [markup of the `RateLimit` HTTP header](https://www.ietf.org/archive/id/draft-ietf-httpapi-ratelimit-headers-04.html#name-expressing-rate-limit-polic)

#### MOTIS

The following properties are defined:
* `endpoint`: Base URL for the API
* `motisVersion`: version of the [motis-server](https://github.com/motis-project/motis/releases)

## Contributing

Note that, by participating in this project, you commit to the [code of conduct](code-of-conduct.md). If you want to contribute to this list, feel free to open an Issue at the [Issues page](https://github.com/public-transport/european-transport-operators/issues).


text:
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at `mail@juliustens.eu`. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]

[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/4/


text:
# List of TRIAS Providers

This is a list of public transport providers that provide a TRIAS API.
Be aware that most of them **do not offer open APIs**, but require you to sign up with them.
To sign up the collected Links are provided.

- [bwegt](https://www.mobidata-bw.de/dataset/trias)
- [Verkehrsverbund Rhein-Neckar (VRN)](https://www.vrn.de/opendata/API)


text:
name: Validate endpoint definitions

on:
  push:
    branches:
      - '*'
  pull_request:
    branches:
      - '*'

jobs:
  verify-json-validation:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Validate JSON
        uses: docker://nhalstead00/validate-json-action:latest
        env:
          INPUT_SCHEMA: schema.json
          INPUT_JSONS: data/*/*.json