├── screenshot.png
├── manifest
├── etc
│ ├── cron.d
│ │ └── root
│ └── supervisor
│ │ └── conf.d
│ │ └── crond.conf
├── var
│ └── www
│ │ └── viewer
│ │ └── dmarcts-report-viewer-config.php
├── entrypoint.sh
└── usr
│ └── bin
│ └── dmarcts-report-parser.conf
├── .github
└── workflows
│ ├── contributors.yml
│ └── docker-image.yml
├── examples
├── docker-compose.postgres.yml
├── env.example
└── docker-compose.mysql.yml
├── Dockerfile
├── README.md
└── Jenkinsfile
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gutmensch/docker-dmarc-report/HEAD/screenshot.png
--------------------------------------------------------------------------------
/manifest/etc/cron.d/root:
--------------------------------------------------------------------------------
1 | 15 * * * * /usr/bin/dmarcts-report-parser.pl -i -d -r 1>>/var/log/nginx/dmarc-reports.log 2>&1
2 |
3 |
--------------------------------------------------------------------------------
/manifest/etc/supervisor/conf.d/crond.conf:
--------------------------------------------------------------------------------
1 | [program:cron]
2 | command=crond -f -L /dev/stdout -c /etc/cron.d
3 | autostart=true
4 | autorestart=true
5 | priority=10
6 | stdout_events_enabled=true
7 | stderr_events_enabled=true
8 |
--------------------------------------------------------------------------------
/manifest/var/www/viewer/dmarcts-report-viewer-config.php:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/.github/workflows/contributors.yml:
--------------------------------------------------------------------------------
1 | name: Contributors
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | contributors:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - uses: wow-actions/contributors-list@v1
12 | with:
13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 | svgPath: CONTRIBUTORS.svg
15 | sort: true
16 | round: true
17 | includeBots: false
18 | userNameHeight: 19
19 | # This job does not have commit powers to the `master` branch
20 | noCommit: true
21 | itemTemplate: >
22 |
23 |
24 |
25 | {{{ name }}}
26 |
27 |
28 | - name: Create Pull Request
29 | uses: peter-evans/create-pull-request@v3
30 | with:
31 | commit-message: '[chore] update contributors svg'
32 | title: '[chore] update contributors svg'
33 | delete-branch: true
34 | assignees: gutmensch
35 | reviewers: gutmensch
36 |
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | tags:
8 | - "v*"
9 | pull_request:
10 | branches:
11 | - master
12 |
13 | jobs:
14 | build-and-release:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 |
20 | - name: Set up QEMU
21 | uses: docker/setup-qemu-action@v2
22 |
23 | - name: Set up Docker Buildx
24 | uses: docker/setup-buildx-action@v2
25 |
26 | - name: Docker meta
27 | id: meta
28 | uses: docker/metadata-action@v4
29 | with:
30 | images: gutmensch/dmarc-report
31 | flavor: latest=true
32 | tags: |
33 | type=ref,event=branch
34 | type=ref,event=pr
35 | type=semver,pattern={{version}}
36 |
37 | - name: Login to DockerHub
38 | if: github.ref_type == 'tag'
39 | uses: docker/login-action@v2
40 | with:
41 | username: ${{ secrets.DOCKERHUB_USERNAME }}
42 | password: ${{ secrets.DOCKERHUB_TOKEN }}
43 |
44 | - name: Build and push
45 | uses: docker/build-push-action@v4
46 | with:
47 | context: .
48 | platforms: linux/amd64, linux/arm64
49 | file: Dockerfile
50 | push: ${{ github.ref_type == 'tag' }}
51 | tags: |
52 | ${{ steps.meta.outputs.tags }}
53 | gutmensch/dmarc-report:latest
54 | labels: ${{ steps.meta.outputs.labels }}
55 |
--------------------------------------------------------------------------------
/examples/docker-compose.postgres.yml:
--------------------------------------------------------------------------------
1 | services:
2 | dmarc-report:
3 | image: "gutmensch/dmarc-report:latest"
4 | hostname: dmarc-report
5 | container_name: dmarc-report
6 | restart: always
7 | depends_on:
8 | db:
9 | condition: service_healthy
10 | ports:
11 | - "80:80"
12 | environment:
13 | - "REPORT_DB_HOST=${DB_HOST:-db}"
14 | - "REPORT_DB_TYPE=${DB_TYPE:-pgsql}"
15 | - "REPORT_DB_PORT=${DB_PORT:-5432}"
16 | - "REPORT_DB_NAME=${DB_NAME:-dmarc_report}"
17 | - "REPORT_DB_USER=${DB_USER:-dmarc_report}"
18 | - "REPORT_DB_PASS=${DB_PASSWORD}"
19 | - "PARSER_IMAP_SERVER=${IMAP_SERVER}"
20 | - "PARSER_IMAP_PORT=${IMAP_PORT:-993}"
21 | - "PARSER_IMAP_USER=${IMAP_USER}"
22 | - "PARSER_IMAP_PASS=${IMAP_PASSWORD}"
23 | - "PARSER_IMAP_READ_FOLDER=${IMAP_READ_FOLDER:-Inbox}"
24 | - "PARSER_IMAP_MOVE_FOLDER=${IMAP_MOVE_FOLDER:-processed}"
25 | - "PARSER_IMAP_MOVE_FOLDER_ERR=${IMAP_MOVE_FOLDER_ERR:-error}"
26 | - "PARSER_IMAP_SSL=${PARSER_IMAP_SSL}"
27 | - "PARSER_IMAP_TLS=${PARSER_IMAP_TLS}"
28 | - "PARSER_IMAP_IGNORE_ERROR=${PARSER_IMAP_IGNORE_ERROR}"
29 | - "PARSER_XML_MAXSIZE=${PARSER_XML_MAXSIZE}"
30 |
31 | db:
32 | image: postgres:latest
33 | restart: always
34 | environment:
35 | - "POSTGRES_DB=${DB_NAME:-dmarc_report}"
36 | - "POSTGRES_USER=${DB_USER:-dmarc_report}"
37 | - "POSTGRES_PASSWORD=${DB_PASSWORD}"
38 | volumes:
39 | - ./run/db:/var/lib/postgresql/data
40 | healthcheck:
41 | test: ["CMD-SHELL", "pg_isready -U dmarc_report"]
42 | interval: 10s
43 | timeout: 10s
44 | retries: 5
--------------------------------------------------------------------------------
/examples/env.example:
--------------------------------------------------------------------------------
1 | # database host address, leave empty for default host "db"
2 | DB_HOST=
3 |
4 | # the database type mysql or pgsql, leave empty for default (depending on your docker-compose.yml)
5 | DB_TYPE=
6 |
7 | # the database port (mysql 3306) (pqsql 5432), leave empty for default (depending on your docker-compose.yml)
8 | DB_PORT=
9 |
10 | # the database name, leave empty for default "dmarc_report"
11 | DB_NAME=
12 |
13 | # the database name, leave empty for default "dmarc_report"
14 | DB_USER=
15 |
16 | # mysql root password. Irrelevant if you are using postgres
17 | ROOT_DB_PASSWORD=
18 |
19 | # database password for the database user
20 | DB_PASSWORD=
21 |
22 | # the email address receiving the DMARC reports
23 | IMAP_USER=
24 |
25 | # the password for the email address receiving the DMARC reports
26 | IMAP_PASSWORD=
27 |
28 | # the server the email address is hosted on
29 | IMAP_SERVER=
30 |
31 | # optional: default is 993 (or 143)
32 | IMAP_PORT=
33 |
34 | # optional: default is "Inbox"
35 | IMAP_READ_FOLDER=
36 |
37 | # optional: default is "processed"
38 | IMAP_MOVE_FOLDER=
39 |
40 | # optional: default is "error"
41 | IMAP_MOVE_FOLDER_ERR=
42 |
43 | # Enable SSL and/or (START-)TLS. Set both to 0 to disable encryption (not recommended)
44 | PARSER_IMAP_SSL=0
45 | PARSER_IMAP_TLS=1
46 |
47 | # Ignore ERROR: message_string() issue experienced with Exchange Online. Set to 1 to enable
48 | PARSER_IMAP_IGNORE_ERROR=0
49 |
50 | # Increase the maximum size of the XML file. (default is 50000 bytes)
51 | # When the size exceeds the maximum, one could experience an error Uncaught ValueError: DOMDocument::loadXML():
52 | # Argument #1 ($source) must not be empty.
53 | PARSER_XML_MAXSIZE=50000
54 |
--------------------------------------------------------------------------------
/examples/docker-compose.mysql.yml:
--------------------------------------------------------------------------------
1 | services:
2 | dmarc-report:
3 | image: "gutmensch/dmarc-report:latest"
4 | hostname: dmarc-report
5 | container_name: dmarc-report
6 | restart: always
7 | depends_on:
8 | db:
9 | condition: service_healthy
10 | ports:
11 | - "80:80"
12 | environment:
13 | - "REPORT_DB_HOST=${DB_HOST:-db}"
14 | - "REPORT_DB_TYPE=${DB_TYPE:-mysql}"
15 | - "REPORT_DB_PORT=${DB_PORT:-3306}"
16 | - "REPORT_DB_NAME=${DB_NAME:-dmarc_report}"
17 | - "REPORT_DB_USER=${DB_USER:-dmarc_report}"
18 | - "REPORT_DB_PASS=${DB_PASSWORD}"
19 | - "PARSER_IMAP_SERVER=${IMAP_SERVER}"
20 | - "PARSER_IMAP_PORT=${IMAP_PORT:-993}"
21 | - "PARSER_IMAP_USER=${IMAP_USER}"
22 | - "PARSER_IMAP_PASS=${IMAP_PASSWORD}"
23 | - "PARSER_IMAP_READ_FOLDER=${IMAP_READ_FOLDER:-Inbox}"
24 | - "PARSER_IMAP_MOVE_FOLDER=${IMAP_MOVE_FOLDER:-processed}"
25 | - "PARSER_IMAP_MOVE_FOLDER_ERR=${IMAP_MOVE_FOLDER_ERR:-error}"
26 | - "PARSER_IMAP_SSL=${PARSER_IMAP_SSL}"
27 | - "PARSER_IMAP_TLS=${PARSER_IMAP_TLS}"
28 | - "PARSER_IMAP_IGNORE_ERROR=${PARSER_IMAP_IGNORE_ERROR}"
29 | - "PARSER_XML_MAXSIZE=${PARSER_XML_MAXSIZE}"
30 |
31 | db:
32 | image: mariadb:10
33 | command: --skip-innodb-read-only-compressed
34 | restart: always
35 | environment:
36 | - "MYSQL_ROOT_PASSWORD=${ROOT_DB_PASSWORD}"
37 | - "MYSQL_DATABASE=${DB_NAME:-dmarc_report}"
38 | - "MYSQL_USER=${DB_USER:-dmarc_report}"
39 | - "MYSQL_PASSWORD=${DB_PASSWORD}"
40 | volumes:
41 | - ./run/db:/var/lib/mysql
42 | healthcheck:
43 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p${ROOT_DB_PASSWORD}"]
44 | interval: 10s
45 | timeout: 10s
46 | retries: 5
47 |
--------------------------------------------------------------------------------
/manifest/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # change according to alpine and php release
4 | PHP_VERSION=81
5 |
6 | # Display PHP error's or not
7 | if [[ "$ERRORS" != "1" ]] ; then
8 | sed -i -e "s/error_reporting =.*/error_reporting = E_ALL/g" /etc/php${PHP_VERSION}/php.ini
9 | sed -i -e "s/display_errors =.*/display_errors = stdout/g" /etc/php${PHP_VERSION}/php.ini
10 | fi
11 |
12 | # Disable opcache?
13 | if [[ -v NO_OPCACHE ]]; then
14 | sed -i -e "s/zend_extension=opcache.so/;zend_extension=opcache.so/g" /etc/php${PHP_VERSION}/conf.d/00_opcache.ini
15 | fi
16 |
17 | # Tweak nginx to match the workers to cpu's
18 | procs=$(cat /proc/cpuinfo | grep processor | wc -l)
19 | sed -i -e "s/worker_processes 5/worker_processes $procs/" /etc/nginx/nginx.conf
20 |
21 | # Copy important env vars for PHP-FPM to access
22 | PHP_ENV_FILE="/etc/php${PHP_VERSION}/php-fpm.d/${PHP_ENV_FILE:-env.conf}"
23 | echo '[www]' > "$PHP_ENV_FILE"
24 | echo 'user = nginx' >> "$PHP_ENV_FILE"
25 | echo 'group = www-data' >> "$PHP_ENV_FILE"
26 | echo 'listen.owner = nginx' >> "$PHP_ENV_FILE"
27 | echo 'listen.group = www-data' >> "$PHP_ENV_FILE"
28 | env | grep -e 'REPORT_DB_TYPE' -e 'REPORT_DB_HOST' -e 'REPORT_DB_PORT' -e 'REPORT_DB_NAME' -e 'REPORT_DB_USER' -e 'REPORT_DB_PASS' | sed "s/\(.*\)=\(.*\)/env[\1] = '\2'/" >> "$PHP_ENV_FILE"
29 |
30 | # compat from older image where variable was not existing
31 | grep -e ^REPORT_DB_PORT "$PHP_ENV_FILE" || echo env[REPORT_DB_PORT] = 3306 >> "$PHP_ENV_FILE"
32 |
33 | # Get and parse dmarc reports once at startup to avoid PHP errors with a new database
34 | if /usr/bin/dmarcts-report-parser.pl -i -d -r > /var/log/nginx/dmarc-reports.log 2>&1; then
35 | echo 'INFO: Dmarc reports parsed successfully'
36 | else
37 | echo 'CRIT: Dmarc reports could not be parsed. Check your IMAP and MYSQL Settings.'
38 | echo -e "DEBUG: Parsing failed with the following output:\n"
39 | cat /var/log/nginx/dmarc-reports.log
40 | exit 1
41 | fi
42 |
43 | # Start supervisord and services
44 | /usr/bin/supervisord -n -c /etc/supervisord.conf
45 |
--------------------------------------------------------------------------------
/manifest/usr/bin/dmarcts-report-parser.conf:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | ### configuration ##############################################################
3 | ################################################################################
4 |
5 | # If IMAP access is not used, config options starting with $imap do not need to
6 | # be set and are ignored.
7 |
8 | $debug = $ENV{'PARSER_DEBUG'} // 0;
9 | $delete_reports = $ENV{'PARSER_DELETE_REPORTS'} // 0;
10 |
11 | $dbname = $ENV{'REPORT_DB_NAME'};
12 | $dbuser = $ENV{'REPORT_DB_USER'};
13 | $dbpass = $ENV{'REPORT_DB_PASS'};
14 | $dbhost = $ENV{'REPORT_DB_HOST'}; # Set the hostname if we can't connect to the local socket.
15 | $dbport = $ENV{'REPORT_DB_PORT'} // 3306;
16 | $dbtype = $ENV{'REPORT_DB_TYPE'} eq 'pgsql' ? 'Pg' : 'mysql';
17 |
18 | if(exists $ENV{PARSER_IMAP_SERVER_WITH_PORT} && defined $ENV{PARSER_IMAP_SERVER_WITH_PORT}) {
19 | my @server_attr = split ':', $ENV{PARSER_IMAP_SERVER_WITH_PORT};
20 | $imapserver = $server_attr[0];
21 | $imapport = $server_attr[1];
22 | } else {
23 | $imapserver = $ENV{'PARSER_IMAP_SERVER'};
24 | $imapport = $ENV{'PARSER_IMAP_PORT'};
25 | }
26 |
27 | $imapuser = $ENV{'PARSER_IMAP_USER'};
28 | $imappass = $ENV{'PARSER_IMAP_PASS'};
29 | $imapssl = $ENV{'PARSER_IMAP_SSL'} // '0'; # If set to 1, remember to change server port to 993 and disable imaptls.
30 | $imaptls = $ENV{'PARSER_IMAP_TLS'} // '1'; # Enabled as the default and best-practice.
31 | $tlsverify = $ENV{'PARSER_IMAP_VERIFY'} // '0'; # Enable verify server cert as the default and best-practice.
32 | $imapignoreerror = $ENV{'PARSER_IMAP_IGNORE_ERROR'} // '0';# set it to 1 if you see an "ERROR: message_string()
33 | # expected 119613 bytes but received 81873 you may
34 | # need the IgnoreSizeErrors option" because of malfunction
35 | # imap server as MS Exchange 2007, ...
36 | $imapreadfolder = $ENV{'PARSER_IMAP_READ_FOLDER'};
37 |
38 | # If $imapmovefolder is set, processed IMAP messages will be moved (overruled by
39 | # the --delete option!)
40 | $imapmovefolder = $ENV{'PARSER_IMAP_MOVE_FOLDER'};
41 | $imapmovefoldererr = $ENV{'PARSER_IMAP_MOVE_FOLDER_ERR'};
42 |
43 | # maximum size of XML files to store in database, long files can cause transaction aborts
44 | $maxsize_xml = $ENV{'PARSER_XML_MAXSIZE'} // 50000;
45 | # store XML as base64 encopded gzip in database (save space, harder usable)
46 | $compress_xml = $ENV{'PARSER_XML_COMPRESS'} // 0;
47 |
48 | # if there was an error during file processing (message does not contain XML or ZIP parts,
49 | # or a database error) the parser reports an error and does not delete the file, even if
50 | # delete_reports is set (or --delete is given). Deletion can be enforced by delete_failed,
51 | # however not for database errors.
52 | $delete_failed = $ENV{'PARSER_DELETE_FAILED'} // 0;
53 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG UPSTREAM_IMAGE=trafex/php-nginx:2.6.0
2 |
3 | FROM $UPSTREAM_IMAGE
4 |
5 | LABEL maintainer="Robert Schumann "
6 |
7 | ENV REPORT_PARSER_SOURCE="https://github.com/techsneeze/dmarcts-report-parser/archive/master.zip" \
8 | REPORT_VIEWER_SOURCE="https://github.com/techsneeze/dmarcts-report-viewer/archive/master.zip"
9 |
10 | USER root
11 |
12 | WORKDIR /
13 |
14 | COPY ./manifest/ /
15 |
16 | RUN set -e -x \
17 | && apk add -U \
18 | bash \
19 | cmake \
20 | expat-dev \
21 | g++ \
22 | gpg \
23 | gzip \
24 | libpq \
25 | libpq-dev \
26 | make \
27 | mariadb-client \
28 | mariadb-connector-c \
29 | mariadb-dev \
30 | musl-obstack \
31 | musl-obstack-dev \
32 | openssl \
33 | openssl-dev \
34 | perl-dev \
35 | perl-utils \
36 | php81-pdo \
37 | php81-pdo_mysql \
38 | php81-pdo_pgsql \
39 | tzdata \
40 | wget \
41 | && wget -4 -q --no-check-certificate -O parser.zip $REPORT_PARSER_SOURCE \
42 | && wget -4 -q --no-check-certificate -O viewer.zip $REPORT_VIEWER_SOURCE \
43 | && unzip parser.zip && cp -av dmarcts-report-parser-master/* /usr/bin/ && rm -vf parser.zip && rm -rvf dmarcts-report-parser-master \
44 | && unzip viewer.zip && cp -av dmarcts-report-viewer-master/* /var/www/viewer/ && rm -vf viewer.zip && rm -rvf dmarcts-report-viewer-master \
45 | && sed -i "1s/^/body { font-family: Sans-Serif; }\n/" /var/www/viewer/default.css \
46 | && sed -i 's%.*listen [::]:8080 default_server;% listen [::]:80 default_server;%g' /etc/nginx/nginx.conf \
47 | && sed -i 's%.*listen 8080 default_server;% listen 80 default_server;%g' /etc/nginx/nginx.conf \
48 | && sed -i 's%.*root /var/www/html;% root /var/www/viewer;%g' /etc/nginx/nginx.conf \
49 | && sed -i 's/.*index index.php index.html;/ index dmarcts-report-viewer.php;/g' /etc/nginx/nginx.conf \
50 | && sed -i 's%files = /etc/supervisor.d/\*.ini%files = /etc/supervisor/conf.d/*.conf%g' /etc/supervisord.conf \
51 | && (echo y;echo o conf allow_installing_outdated_dists yes;echo o conf prerequisites_policy follow;echo o conf commit)|cpan \
52 | && for i in \
53 | IO::Socket::SSL \
54 | CPAN \
55 | CPAN::DistnameInfo \
56 | File::MimeInfo \
57 | IO::Compress::Gzip \
58 | Getopt::Long \
59 | Mail::IMAPClient \
60 | Mail::Mbox::MessageParser \
61 | MIME::Base64 \
62 | MIME::Words \
63 | MIME::Parser \
64 | MIME::Parser::Filer \
65 | XML::Parser \
66 | XML::Simple \
67 | DBI \
68 | # XXX: pinning to a version, which does not suffer from mariadb 10 version comparison issues
69 | # TODO: replace with DBD::mysql again, when issue is resolved
70 | # https://forum.bestpractical.com/t/mysql-dependency-error-with-mariadb-and-debian-12/38748/2
71 | DVEEDEN/DBD-mysql-4.052.tar.gz \
72 | DBD::Pg \
73 | Socket \
74 | Socket6 \
75 | PerlIO::gzip \
76 | ; do cpan install $i; done \
77 | && apk del mariadb-dev expat-dev openssl-dev perl-dev g++ cmake make musl-obstack-dev libpq-dev
78 |
79 | HEALTHCHECK --interval=1m --timeout=3s CMD curl --silent --fail http://127.0.0.1:80/fpm-ping
80 |
81 | EXPOSE 80
82 |
83 | CMD ["/bin/bash", "/entrypoint.sh"]
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # docker-dmarc-report  [](https://registry.hub.docker.com/u/gutmensch/dmarc-report/)
2 |
3 | This image is intended to combine a dmarc report parser (see https://github.com/techsneeze/dmarcts-report-parser by TechSneeze.com and John Bieling) with a report viewer (see https://github.com/techsneeze/dmarcts-report-viewer/ by the same people) into a runnable docker image / microservice.
4 |
5 | It fetches dmarc report mails regularly from an IMAP server, stores them into a MySQL DB and visualizes them via Webserver/PHP module.
6 |
7 | ## Howto
8 |
9 | 1. Create a \_dmarc.example.com TXT DNS record for your domain, containg an IMAP postbox, e.g.
10 |
11 | ```bash
12 | 17:18 $ dig TXT _dmarc.schumann.link +short
13 | "v=DMARC1\; p=quarantine\; fo=1\; rua=mailto:dmarc@schumann.link\; ruf=mailto:dmarc@schumann.link\; adkim=s\; aspf=s\;"
14 | ```
15 |
16 | 1. Create a MySQL Database and a user for this service
17 |
18 | 1. Run this docker image with below mentioned env vars
19 |
20 | 1. Access port 80 on the container (or 443) or put it behind a reverse proxy to view reports
21 |
22 | ```bash
23 | docker pull gutmensch/dmarc-report
24 | docker run -e ... -ti gutmensch/dmarc-report
25 | ```
26 |
27 | New dmarc reports will be fetched every 15 minutes past the hour, every hour. Therefore it can take up to one hour for the first report to be fetched.
28 |
29 | ## Versions for last build latest and docker image tag 1.4
30 |
31 | dmarcts report viewer: 2024-02-04
32 |
33 | dmarcts report parser: 2024-02-04
34 |
35 | CAUTION: The old gutmensch/dmarc-report:latest image (older alpine, php5, etc.) is available still as gutmensch/dmarc-report:0.5. The current latest (and 1.0) uses the latest alpine version, newer MySQL client libraries, newer OpenSSL, etc. and improves compatibilitiy with MySQL 8+.
36 |
37 | ## Frontend Screenshot
38 |
39 | 
40 |
41 | ## Sample docker compose / Environment variables
42 |
43 | Make sure to create the IMAP-Folders for processed and error reports before the cron job runs!
44 |
45 | The default foldernames are are [`error`](examples/env.example) & [`processed`](examples/env.example) but they can be changed within the [`env-file`](examples/env.example).
46 |
47 | Make sure to rename the [`env.example`](examples/env.example) file to `.env` and adjust the values to your needs.
48 |
49 | You can find templates for both, [`postgreql`](examples/docker-compose.postgres.yml)
50 | and [`mysql`](examples/docker-compose.mysql.yml)
51 | db in the [`examples`](examples) directory. Just rename the setup you want to use to `docker-compose.yml`.
52 |
53 |
54 |
55 |
56 | ## Manual update
57 |
58 | If you are using the docker-compose file above, you can use this command to trigger an manual update. It will fetch the latest reports and parse them.
59 |
60 | ```bash
61 | docker compose exec dmarc-report /usr/bin/dmarcts-report-parser.pl -i -d -r=1
62 | ```
63 |
64 | ## Optional extended configuration
65 |
66 | For further optional configuration see the docker-compose [`env-file`](examples/env.example).
67 |
68 | ## Contributors
69 |
70 |
71 |
72 | ## Stargazers over time
73 |
74 | [](https://starchart.cc/gutmensch/docker-dmarc-report)
75 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
2 | import java.text.SimpleDateFormat
3 |
4 |
5 | DOCKER_IMAGE_NAME = ''
6 | DOCKER_IMAGE = ''
7 | DOCKER_ARGS = '--network=services_default'
8 | DOCKER_REGISTRY = 'registry.n-os.org:5000'
9 |
10 |
11 | properties([
12 | disableConcurrentBuilds(),
13 | parameters([
14 | booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: 'Do you want to run the build with tests?')
15 | ])
16 | ])
17 |
18 |
19 | node {
20 | try {
21 | pipeline()
22 | }
23 | catch(e) {
24 | setBuildStatus(e.toString().take(140), 'FAILURE')
25 | throw e
26 | }
27 | finally {
28 | cleanup()
29 | }
30 | }
31 |
32 |
33 | /*
34 | ******************************************************************
35 |
36 | standard functions
37 | these functions below implement the standard docker image pipeline
38 |
39 | ******************************************************************
40 | */
41 | def pipeline() {
42 |
43 | stage('checkout git') {
44 | checkout scm
45 | setBuildStatus('In progress...', 'PENDING')
46 | }
47 |
48 | // https://docs.cloudbees.com/docs/admin-resources/latest/plugins/docker-workflow
49 | stage('build image') {
50 | DOCKER_IMAGE_NAME = "${DOCKER_REGISTRY}/${getDockerImage()}:${getDockerTag()}"
51 | DOCKER_IMAGE = docker.build(DOCKER_IMAGE_NAME, "--no-cache ${DOCKER_ARGS} .")
52 | }
53 |
54 | stage('run tests') {
55 | if (fileExists('./test/run.sh') && !params.SKIP_TESTS) {
56 | DOCKER_IMAGE.inside("${DOCKER_ARGS} --entrypoint=") {
57 | sh 'bash /usr/build/test/run.sh'
58 | }
59 | }
60 | else {
61 | Utils.markStageSkippedForConditional('run tests')
62 | }
63 | }
64 |
65 | stage('push image') {
66 | if (BRANCH_NAME == 'master') {
67 | DOCKER_IMAGE.push()
68 | }
69 | else {
70 | Utils.markStageSkippedForConditional('push image')
71 | }
72 | }
73 |
74 | stage('delete image') {
75 | if (BRANCH_NAME == 'master') {
76 | Utils.markStageSkippedForConditional('delete image')
77 | }
78 | else {
79 | deleteDockerImage(DOCKER_IMAGE_NAME)
80 | }
81 | setBuildStatus('Success', 'SUCCESS')
82 | }
83 | }
84 |
85 | void deleteDockerImage(image) {
86 | sh(script: "docker rmi -f ${image}")
87 | }
88 |
89 | void cleanup() {
90 | stage('schedule cleanup') {
91 | build job: '/maintenance/starter', wait: false
92 | }
93 | }
94 |
95 | String getDockerImage() {
96 | return sh(script: "echo '${JOB_NAME}' | awk -F/ '{print \$(NF-1)}' | sed 's%docker-%%'", returnStdout: true).trim()
97 | }
98 |
99 | String getDockerTag() {
100 | def shortHash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
101 | def date = new Date()
102 | def sdf = new SimpleDateFormat("yyyyMMddHHmmss")
103 | // semver in TAG_ID file or reference to ARG in Dockerfile
104 | if (!fileExists('./TAG_ID')) {
105 | return "${sdf.format(date)}.${shortHash}.b${BUILD_ID}"
106 | }
107 | def tagId = sh(script: 'cat ./TAG_ID', returnStdout: true).trim()
108 | if (tagId ==~ /^[A-Z_]+$/) {
109 | return sh(script: "awk -F= '/ARG ${tagId}=/{print \$2}' Dockerfile", returnStdout: true).trim()
110 | }
111 | else {
112 | return tagId
113 | }
114 | }
115 |
116 | void setBuildStatus(message, state) {
117 | def repoUrl = sh(script: 'git config --get remote.origin.url', returnStdout: true).trim()
118 | step([
119 | $class: "GitHubCommitStatusSetter",
120 | reposSource: [$class: "ManuallyEnteredRepositorySource", url: repoUrl],
121 | contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/build-status"],
122 | errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
123 | statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
124 | ]);
125 | }
126 |
--------------------------------------------------------------------------------