{"id":13581629,"url":"https://github.com/letsencrypt/ct-woodpecker","last_synced_at":"2025-09-21T01:10:38.165Z","repository":{"id":34118034,"uuid":"132651876","full_name":"letsencrypt/ct-woodpecker","owner":"letsencrypt","description":"A tool to monitor a certificate transparency log for operational problems","archived":false,"fork":false,"pushed_at":"2023-07-27T20:25:42.000Z","size":16558,"stargazers_count":183,"open_issues_count":14,"forks_count":20,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-05-07T15:47:49.623Z","etag":null,"topics":["alert-manager","certificate-transparency","ct","ct-woodpecker","grafana","monitoring","pki","prometheus","x509"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/letsencrypt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-05-08T18:55:25.000Z","updated_at":"2025-03-06T02:16:33.000Z","dependencies_parsed_at":"2024-01-14T09:58:32.929Z","dependency_job_id":"326067e4-8006-4337-8a55-6c05aa7e34bb","html_url":"https://github.com/letsencrypt/ct-woodpecker","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/letsencrypt/ct-woodpecker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letsencrypt%2Fct-woodpecker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letsencrypt%2Fct-woodpecker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letsencrypt%2Fct-woodpecker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letsencrypt%2Fct-woodpecker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/letsencrypt","download_url":"https://codeload.github.com/letsencrypt/ct-woodpecker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letsencrypt%2Fct-woodpecker/sbom","scorecard":{"id":585944,"data":{"date":"2025-08-11","repo":{"name":"github.com/letsencrypt/ct-woodpecker","commit":"cf2d5cd553b2ebde3bcf1b21e1571e0957c8dfe6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: topLevel 'contents' permission set to 'read': .github/workflows/golangci-lint.yml:14","Info: topLevel 'pull-requests' permission set to 'read': .github/workflows/golangci-lint.yml:15","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: Mozilla Public License 2.0: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/golangci-lint.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/letsencrypt/ct-woodpecker/golangci-lint.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/golangci-lint.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/letsencrypt/ct-woodpecker/golangci-lint.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/golangci-lint.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/letsencrypt/ct-woodpecker/golangci-lint.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/letsencrypt/ct-woodpecker/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/letsencrypt/ct-woodpecker/test.yml/main?enable=pin","Warn: containerImage not pinned by hash: docker/ct-malformed/Dockerfile:1","Warn: containerImage not pinned by hash: docker/ct-malformed/Dockerfile:15: pin your Docker image by updating alpine:3.17.3 to alpine:3.17.3@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126","Warn: containerImage not pinned by hash: docker/ct-test-srv/Dockerfile:1","Warn: containerImage not pinned by hash: docker/ct-test-srv/Dockerfile:15: pin your Docker image by updating alpine:3.17.3 to alpine:3.17.3@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126","Warn: containerImage not pinned by hash: docker/ct-woodpecker/Dockerfile:1","Warn: containerImage not pinned by hash: docker/ct-woodpecker/Dockerfile:15: pin your Docker image by updating alpine:3.17.3 to alpine:3.17.3@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126","Warn: goCommand not pinned by hash: vendor/github.com/fullstorydev/grpcurl/mk-test-files.sh:24","Warn: goCommand not pinned by hash: vendor/github.com/fullstorydev/grpcurl/mk-test-files.sh:25","Warn: goCommand not pinned by hash: vendor/github.com/json-iterator/go/build.sh:10","Warn: goCommand not pinned by hash: vendor/google.golang.org/grpc/regenerate.sh:35","Warn: goCommand not pinned by hash: vendor/google.golang.org/grpc/vet.sh:37","Warn: goCommand not pinned by hash: .github/workflows/test.yml:23","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   6 containerImage dependencies pinned","Info:   7 out of  13 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"22 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2025-3372 / GHSA-6wxm-mpqj-6jpf","Warn: Project is vulnerable to: GO-2024-2528","Warn: Project is vulnerable to: GO-2024-2529","Warn: Project is vulnerable to: GO-2024-2530","Warn: Project is vulnerable to: GO-2023-2331 / GHSA-8pgv-569h-w5rw","Warn: Project is vulnerable to: GO-2024-2961","Warn: Project is vulnerable to: GO-2023-2402 / GHSA-45x7-px36-x8w8","Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GO-2022-0969 / GHSA-69cg-p879-7622","Warn: Project is vulnerable to: GO-2022-1144 / GHSA-xrjj-mj9h-534m","Warn: Project is vulnerable to: GO-2023-1571 / GHSA-vvpx-j8f3-3w6h","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GO-2023-2153 / GHSA-m425-mq94-257g / GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2025-3488 / GHSA-6v2p-p543-phr9","Warn: Project is vulnerable to: GO-2022-1059 / GHSA-69ch-w2m2-3vjp","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T20:30:46.836Z","repository_id":34118034,"created_at":"2025-08-20T20:30:46.836Z","updated_at":"2025-08-20T20:30:46.836Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276180644,"owners_count":25598706,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-20T02:00:10.207Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alert-manager","certificate-transparency","ct","ct-woodpecker","grafana","monitoring","pki","prometheus","x509"],"created_at":"2024-08-01T15:02:08.541Z","updated_at":"2025-09-21T01:10:38.106Z","avatar_url":"https://github.com/letsencrypt.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# CT Woodpecker\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/letsencrypt/ct-woodpecker/raw/main/logo.jpg\" alt=\"ct-woodpecker: poking holes in logs\"/\u003e\n\u003cp\u003e\n\n`ct-woodpecker` pokes holes in logs and finds bugs. It is a tool for monitoring\na [Certificate Transparency][ct] log for operational problems.\n\nGet started by [running a full example environment in Docker](#quick-start) with\none command.\n\n---\n\n* [About](#about)\n  * [Limitations](#limitations)\n* [Installation](#installation)\n  * [Quick-start](#quick-start)\n  * [Production Setup](#production-setup)\n* [Collected Metrics](#collected-metrics)\n* [Example Configuration](#example-configuration)\n* [Utilities](#utilities)\n* [Contributing](#contributing)\n* [Photo Credit](#photo-credit)\n\n## About\n\n`ct-woodpecker` is designed primarily for helping log operators maintain insight\ninto the stability and performance of their logs. It is not a complete\nstand-alone monitoring solution and is instead designed to integrate with\n[Prometheus][prometheus], [Grafana][grafana], and [AlertManager][alertmanager].\n\n`ct-woodpecker` plays some parts of both the \"Monitor\" role and the \"Submitter\"\nrole described in [RFC 6962 Section 5][rfc6962sec5] but is not designed to\nfulfill the complete role of an independent monitor or auditor.\n\nAs a Monitor, `ct-woodpecker` fetches the current STH from a log at a regular\ninterval and emits Prometheus stats related to the STH age, the fetch latecy,\nand any errors that occur getting the STH or validating the signature.\n`ct-woodpecker` will also emit similar stats produced validating consistency\nproofs between the current STH and the previous STH.\n\nAs a Submitter `ct-woodpecker` regularly issues its own test certificates using\na test CA that log operators can choose to add to their allowed roots.\n`ct-woodpecker` can emit stats about latency and provides a way for log\noperators to easily monitor certificate and pre-certificate submission.\n\nAfter submitting test certificates `ct-woodpecker` periodically fetches new\nentries from the log and emits stats about the oldest certificate it has\nsubmitted that hasn't yet been merged into the log's merkle tree. This provides\nlog operators with a way to track and enforce their own maximum-merge-delay (MMD).\n\n### Limitations\n\nRemember that `ct-woodpecker` is not a complete Monitor or Auditor. Most\nnotably:\n\n* `ct-woodpecker` does not fetch all entries in the monitored log's tree to\n   attempt to confirm the tree made from fetched entries produces observed STH\n   hashes.\n\n* `ct-woodpecker` does not request or validate Merkle audit proofs for SCT/STH\n  pairs to prove inclusion.\n\n* `ct-woodpecker` does not verify that **any** two STHs from the same log can be\n   verified by requesting a consistency proof. Presently it only verifies\n   linearly observed STHs with consistency proofs.\n\n## Installation\n\n### Quick-start\n\nTo get started with an environment suitable for testing out `ct-woodpecker` or doing development work install [Docker][docker] and [Docker Compose][docker-compose] and then run the following command in the `ct-woodpecker` repo root:\n\n      docker-compose up\n\nThis will create and configure:\n\n1. A `mysql` container running MariaDB.\n1. A `ct-test-srv` container running two in-memory mock CT logs (`log-one` and\n   `log-two`).\n1. A `ct-woodpecker` container configured to monitor `log-one` and `log-two`.\n1. An `alertmanager` container running [AlertManager][alertmanager].\n1. A `prometheus` container running [Prometheus][prometheus] configured to\n   scrape the `ct-woodpecker` stats and use example alert rules with the\n   `alertmanager` container.\n1. A `grafana` container running [Grafana][grafana] configured with a data\n   source for the `prometheus` container and some example `ct-woodpecker`\n   dashboards.\n\nThe following URLs can be used to access the web interfaces of the monitoring\ncomponents:\n\n* Prometheus web interface: `http://10.40.50.4:9090`\n* AlertManager web interface: `http://10.40.50.5:9093`\n* Grafana web interface (username `woodpecker`, password `woodpecker`): `http://10.40.50.6:3000`\n\nThe provided `ct-test-srv` instances offer a small API that can be used to\neasily test `ct-woodpecker` and the associated monitoring in an end-to-end\nsetting.\n\nFor example, you can break certificate submission for `log-two` by making it\nreturn a mock 404 response to add-chain requests:\n\n       curl -X POST \\\n            -d '{\"path\":\"/ct/v1/add-chain\",\"code\":404,\"response\":{\"error\":\"oh noes!\"}}' \\\n            localhost:4601/add-mock\n\nShortly afterwards (2-4m) you can expect the `CertSubmissionErrors` alert to be\nfiring in `http://localhost:9090/alerts` based on the `ct-woodpecker` container\nbeing unable to submit certificates to `log-two`.\n\nYou can cause the alert to recover by removing `log-two`'s add-chain mock\nby running:\n\n       curl -X POST \\\n            -d '{\"path\":\"/ct/v1/add-chain\"}' \\\n            localhost:4601/clear-mock\n\nThe `ct-test-srv` logs also support setting mock STHs, creating inconsistent tree\nviews, and controlling when submitted certificates are integrated into the tree.\nSee the [cttestsrv management_handlers.go][cttestsrv-management-handlers] for\nmore information.\n\n### Production setup\n\nWe don't recommend you use the Docker Compose environment for anything beyond\ntesting and development. Tailoring `ct-woodpecker` for production in your\nenvironment is situation dependent but in general a production `ct-woodpecker`\ndeploy needs:\n\n1. A production ready deployment of [Prometheus][prometheus],\n   [Grafana][grafana], and [AlertManager][alertmanager].\n1. A dedicated low privilege `ct-woodpecker` user.\n1. An optional test issuer certificate and private key for certificate\n   submission. (See the [ct-woodpecker-genissuer](#utilities) command for more).\n1. A copy of the `ct-woodpecker` binary installed somewhere in `$PATH` (e.g.\n   `/usr/local/bin`).\n1. A configured MariaDB database. This means a database, a database user, and\n   initialized tables created using the schema from `storage/mysql/schema.sql`.\n1. A configuration dir `/etc/ct-woodpecker` and config file\n   `/etc/ct-woodpecker/config.json`.\n1. A systemd unit to keep the `ct-woodpecker` service running and to start it at\n   system boot.\n\nAn example [systemd unit](examples/ct-woodpecker.service) and [config\nfile](examples/config.dist.json) are provided to help you get started.\n\nExample Prometheus alerts and Grafana dashboards are also provided in the\n[examples/monitoring_and_alerting](examples/monitoring_and_alerting/) directory.\n\n## Collected Metrics\n\n`ct-woodpecker` exports many [Prometheus][prometheus] metrics on the configured\n`metricsAddr` for monitoring purposes. Below is a table of the metric name, the\ntype, the labels used to slice the metric, and a description.\n\n| Metric Name      | Metric Type   | Labels              | Description                                  |\n| ---------------- |---------------|---------------------|:---------------------------------------------|\n| `sth_timestamp` | GaugeVec | `uri` | Timestamp of fetched STH |\n| `sth_age`       | GaugeVec | `uri`            | Elapsed time since timestamp of fetched STH |\n| `sth_failures`  | CounterVec | `uri` | Count of failures fetching a STH |\n| `sth_fetch_total`  | CounterVec | `uri` | Count of total number of get-sth calls made against each monitored CT log |\n| `sth_latency`   | HistogramVec | `uri` | Latency of fetching a STH |\n| `sth_proof_latency` | HistogramVec | `uri` | Latency of fetching a STH consistency proof |\n| `sth_inconsistencies` | CounterVec | `uri`, `type` | Count of instances two STHs could not be proved consistent |\n| `cert_submit_latency` | HistogramVec | `uri`, `precert` | Latency from submitting a cert or precert |\n| `cert_submit_results` | CounterVec | `uri`, `status`, `precert`, `duplicate` | Result from submitting a cert or precert |\n| `cert_storage_failures` | CounterVec | `uri`, `type` | Count of instances a cert/SCT couldn't be saved to the local DB to watch for inclusion |\n| `stored_scts` | CounterVec | `uri` | Count of unique cert/SCTs retrieved and stored in the db |\n| `oldest_unincorporated_cert` | GaugeVec | `uri` |Number of seconds since the oldest cert waiting on incorporation was submitted |\n| `unincorporated_certs` | GaugeVec | `uri` | Number of certs/SCTs submitted but not yet incorporated |\n| `inclusion_checker_errors` | CounterVec | `uri`, `type` | Number of errors encountered attemtping to check for cert inclusion |\n\n* Possible `sth_inconsistency` `type` values are:\n  * `\"equal-treesize-inequal-hash\"` for when two STH's have the same treesize and different hashes.\n  * `\"failed-to-get-proof\"` for when an error occurs fetching the consistency proof.\n  * `\"failed-to-verify-proof\"` for when a returned STH consistency proof can't\n  be validated.\n\n* Possible `cert_submit_results` `status` values are:\n  * `\"fail\"` for failed submissions.\n  * `\"ok\"` for successful submissions.\n\n* `cert_submit_results` will have a `precert=\"true\"` label when the submission was a precert.\n\n* `cert_submit_results` will have a `duplicate=\"true\"` label when the submission was a resubmission of a previously submitted cert/precert.\n\n* Possible `cert_storage_failures` `type` values are:\n  * `\"marshalling\"` for failures to marshal a returned SCT for storage.\n  * `\"storing\"` for failures to insert the cert/SCT into the DB.\n\n* Possible `inclusion_checker_errors` `type` values are:\n  * `\"getIndex\"` for failures to get the current stored tree index from the DB.\n  * `\"getUnseen\"` for failures to find unseen certs/SCTs in the DB.\n  * `\"getSTH\"` for failures to fetch an STH to determine entries needing to be\n  fetched.\n  * `\"getEntries\"` for failures to get entries from the log.\n  * `\"checkEntries\"` for failures to check unseen certs against the returned new\n  entries.\n  * `\"updateIndex\"` for failures to write a new tree index to the DB.\n\n## Example Configuration\n\n```\n{\n  \"metricsAddr\": \":1971\",\n  \"dbURI\": \"woody@tcp(10.40.50.7:3306)/woodpeckerdb\",\n  \"dbPasswordFile\": \"test/config/db_password\",\n  \"fetchConfig\": {\n    \"interval\": \"20s\",\n    \"timeout\": \"5s\"\n  },\n  \"submitConfig\": {\n    \"interval\": \"5s\",\n    \"timeout\": \"5s\",\n    \"certIssuerKeyPath\": \"/test/issuer.key\",\n    \"certIssuerPath\": \"/test/issuer.pem\"\n  },\n  \"inclusionConfig\": {\n    \"interval\": \"30s\",\n    \"maxGetEntries\": 3000\n  },\n  \"logs\": [\n    {\n      \"uri\": \"http://log-one:4600\",\n      \"key\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYggOxPnPkzKBIhTacSYoIfnSL2jPugcbUKx83vFMvk5gKAz/AGe87w20riuPwEGn229hKVbEKHFB61NIqNHC3Q==\",\n      \"windowStart\": \"2000-01-01T00:00:00Z\",\n      \"windowEnd\": \"2001-01-01T00:00:00Z\",\n      \"minEntry\": 10,\n      \"submitPreCert\": false,\n      \"submitCert\": true\n    },\n    {\n      \"uri\": \"http://log-two:4601\",\n      \"key\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKtnFevaXV/kB8dmhCNZHmxKVLcHX1plaAsY9LrKilhYxdmQZiu36LvAvosTsqMVqRK9a96nC8VaxAdaHUbM8EA==\",\n      \"windowStart\": \"2019-01-01T00:00:00Z\",\n      \"windowEnd\": \"2099-01-01T00:00:00Z\",\n      \"minEntry\": 1,\n      \"submitPreCert\": false,\n      \"submitCert\": true\n    }\n  ]\n}\n```\n\n* **metricsAddr** - a bind address for the `ct-woodpecker` Prometheus metrics\n  server.\n\n* **dbURI** - a [MySQL DSN URL](https://github.com/go-sql-driver/mysql#dsn-data-source-name) specifying\n  the DB username, address, and database name. _NOTE:_ The database user\n  password should be provided in a separate file via the \"dbPasswordFile\" config\n  parameter.\n\n* **dbPasswordFile** - a filepath for a file containing the DB user password.\n  _NOTE_: File must have mode `0600`.\n\n* **fetchConfig** - global configuration related to periodic STH fetching.\n\n  * **interval** - a duration string describing the time period between fetching STHs\n\n  * **timeout** - a duration string describing the timeout for fetching an STH.\n\n* **submitConfig** - global configuration related to periodic cert issuance and\n  submission. May be omitted.\n\n  * **interval** - a duration string describing the time period between attempts\n    to issue and submit certs/precerts.\n\n  * **timeout** - a duration string describing the timeout for submitting\n    a cert/precert.\n\n  * **certIssuerKeyPath** - a filepath for a file containing a PEM encoded\n  RSA/ECDSA private key corresponding to the public key in the\n  **certIssuerPath** PEM encoded intermediate certificate.\n\n  * **certIssuerPath** - a filepath for a file containing a PEM encoded x509\n  certificate to use as the issuer for certificates generated for submitting\n  to logs.\n\n* **inclusionConfig** global configuration related to checking that certificates\n  issued periodically by `ct-woodpecker` were included in the monitored logs.\n\n  * **interval** - a duration string describing the time period between attempts\n    to check unseen certificates for inclusion.\n\n  * **maxGetEntries** - the maximum number of log entries to process each\n  interval. `ct-woodpecker` will make a series of `get-entries` calls for\n  entries to process until it gets `maxGetEntries` entries or reaches the tree\n  head.\n\n  * **startIndex** - an optional integer specifying the treesize to start\n  checking for inclusion from. This is useful if you start `ct-woodpecker`\n  monitoring against a log that already has a large tree, since it lets\n  `ct-woodpecker` skip ahead to the `startIndex`.\n\n* **logs** - an array of one or more CT logs to be configured. Each log is\n  composed of a config object with the following fields:\n\n  * **uri** - the log's URI.\n\n  * **key** - the log's public key (PEM encoded as a single line without the PEM\n  header/footer).\n\n  * **minEntry** - log index to start inclusion checking from, for monitoring large\n  pre-existing logs.\n\n  * **windowStart** - (optional) for a sharded log the `windowStart` specifies\n  the begin date for the shard's accepted validity window. `ct-woodpecker` will\n  ensure the certificates it generates for this log have a `notAfter` within the\n  `windowStart` and `windowEnd`\n\n  * **windowEnd** - (optional) for a sharded log the `windowEnd` specifies\n  the end date for the shard's accepted validity window. `ct-woodpecker` will\n  ensure the certificates it generates for this log have a `notAfter` within the\n  `windowStart` and `windowEnd`\n\n  * **submitPreCert** - if true then precertificates for this log will be\n  generated and submitted based on the global `inclusionConfig`\n\n  * **submitCert** - if true then final certificates for this log will be\n  generated and submitted based on the global `inclusionConfig`\n\n## Utilities\n\n`ct-woodpecker` also provides two additional utilities:\n\n1. `ct-malformed` - a tool for generating malformed CT traffic to\n   fuzz/loadtest a log.\n\n2. `ct-woodpecker-genissuer` - a small tool for creating a one-off CA\n   certificate and private key suitable for use with the `ct-woodpecker`\n   `certSubmitter` config.\n\n## Contributing\n\nPlease open an issue before starting on substantial features or code changes. We\nwould love to help talk through the possible design choices before putting code\nto file.\n\nRoughly the design of `ct-woodpecker` separates things into the following\npackage hiearchy:\n\n* `cmd/` - individual binaries (`ct-woodpecker`, `ct-malformed`).\n* `woodpecker/` - top level concerns related to monitoring all of the configured\n   logs. The `woodpecker` package does most of the heavy lifting for the\n   `ct-woodpecker` command.\n* `monitor/` - the core monitoring logic.\n* `storage/` - code related to MySQL and persistent storage.\n* `pki/` - general PKI utilities mostly used for test certificate issuance.\n* `test/` - convenience tools for unit tests.\n* `test/cttestsrv` - a purpose built in-memory mock CT log for integration\n   testing.\n\nAll pull requests must be reviewed by one of the maintainers before merging.\nWe expect all changes to have robust unit tests.\n\n## Photo credit\n\nThe `ct-woodpecker` repository logo image was provided by a [Pileated\nWoodpecker][pileated] living in the Laurentides region of Quebec, Canada.\nPhotographed by [@cpu][cpu] March 2018.\n\n[ct]: https://www.certificate-transparency.org\n[rfc6962]: https://tools.ietf.org/html/rfc6962\n[rfc6962sec5]: https://tools.ietf.org/html/rfc6962#section-5\n[prometheus]: https://prometheus.io/\n[grafana]: https://grafana.com/\n[alertmanager]: https://prometheus.io/docs/alerting/alertmanager/\n[docker]: https://docs.docker.com/install/\n[docker-compose]: https://docs.docker.com/compose/install/\n[pileated]: https://en.wikipedia.org/wiki/Pileated_woodpecker\n[cpu]: https://github.com/cpu\n[cttestsrv-management-handlers]: https://github.com/letsencrypt/ct-woodpecker/blob/main/test/cttestsrv/management_handlers.go\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fletsencrypt%2Fct-woodpecker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fletsencrypt%2Fct-woodpecker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fletsencrypt%2Fct-woodpecker/lists"}