Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9c59d27
Add support for tiled CT logs
mimi89999 Jan 9, 2026
5ff73a0
Merge pull request #79 from mimi89999/tiled
d-Rickyy-b Jan 25, 2026
bcb2de6
docs: add sample config for custom tiled logs
d-Rickyy-b Jan 25, 2026
8359b42
feat: ability to add custom tiled logs via config
d-Rickyy-b Jan 25, 2026
f17d7fd
chore: add todo comment as reference to undealt issue
d-Rickyy-b Jan 25, 2026
c1cc78c
fix: prevent deadlock from happening
d-Rickyy-b Feb 27, 2026
95bc9c5
test: add unittest to check for deadlock regression
d-Rickyy-b Feb 27, 2026
7e24888
refactor: remove debug print statements
d-Rickyy-b Feb 27, 2026
cdeb9c2
fix: add metrics for new logs
d-Rickyy-b Mar 1, 2026
3cac44c
refactor: fix spelling
d-Rickyy-b Mar 1, 2026
06af3ee
fix: remove verbose log statement
d-Rickyy-b Mar 1, 2026
b50bd56
docs: fix wrong tags in changelog.md
d-Rickyy-b Mar 1, 2026
8e67407
docs: disable additional_logs in sample config file
d-Rickyy-b Mar 1, 2026
b8088fe
docs: update changelog with v1.9.0-beta.3 changes
d-Rickyy-b Mar 1, 2026
b9e5e67
feat(docker)!: move config to own directory
d-Rickyy-b Mar 12, 2026
e6337e7
refactor: improve log output in logmetrics
d-Rickyy-b Mar 12, 2026
a0f3303
fix: ensure correct baseURL for tiled logs
d-Rickyy-b Mar 12, 2026
9502a81
fix: fetch latest checkpoint for tiled logs for -create-index-file
d-Rickyy-b Mar 12, 2026
67feff9
refactor: use cobra for cli flag parsing
d-Rickyy-b Mar 18, 2026
43406a2
feat: implement viper for config management
d-Rickyy-b Mar 23, 2026
14a4dd8
docs: add comment about maps.copy
d-Rickyy-b Mar 23, 2026
8ae3653
refactor: use switch statement instead of if statement
d-Rickyy-b Mar 23, 2026
9f6a658
feat(cli): add validate subcommand
d-Rickyy-b Mar 23, 2026
ef7b842
refactor: fix typos
d-Rickyy-b Mar 23, 2026
b9a3af0
refactor: use slices.Contains instead of custom loop
d-Rickyy-b Mar 23, 2026
db2b81d
fix: ignore value of ctIndex
d-Rickyy-b Mar 23, 2026
d053de2
test: use proper function name in config test
d-Rickyy-b Mar 23, 2026
25d4680
docs: update changelog
d-Rickyy-b Mar 23, 2026
2cd95a0
ci: update github actions workflow dependencies
d-Rickyy-b Mar 23, 2026
e045980
ci(goreleaser): include docker sample config
d-Rickyy-b Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ dockers:
goarch: amd64
use: buildx
extra_files:
- config.sample.yaml
- config.docker.yaml
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
Expand All @@ -62,7 +62,7 @@ dockers:
goarch: arm64
use: buildx
extra_files:
- config.sample.yaml
- config.docker.yaml
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/changelog_reminder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Changelog Reminder
uses: mskelton/changelog-reminder-action@v3
with:
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/release_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,31 @@ jobs:
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0 # See: https://goreleaser.com/ci/actions/

- name: Setup QEMU # Used for cross-compiling with goreleaser / docker
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4

- name: Setup Docker Buildx # Used for cross-compiling with goreleaser / docker
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4

- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
uses: goreleaser/goreleaser-action@v7
with:
version: latest
args: release --clean --config .github/goreleaser.yml
Expand Down
13 changes: 9 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Ability to store and resume processing of certs from where it left off after a restart - see sample config "recovery" (#49)
- New CLI switch for creating an index file from a CT log (#49)
- Support for [Static CT](https://github.com/C2SP/C2SP/blob/main/static-ct-api.md) logs
- Check for retired CT logs and prevent them from being watched / stop watching them (#77)
- Accept websocket connections from all origins
- Option to disable the default logs provided by Google - see sample config "disable_default_logs"
- Use of cobra for CLI argument parsing. New commands for displaying version and creating an index file
### Changed
- The configuration file for the docker container is now read from the /app/config/ directory (b9e5e6)
### Removed
- Non-functional Dodo log from sample config (#78)
### Fixed
- Properly remove stopped ct log workers (#74)
- Added missing fields certificatePolicies and ctlPoisonByte (#85)
- Prevent race condition caused by simultaneous rw access to logmetrics
- Prevent race condition caused by simultaneous rw access to logmetrics (#91)
- Properly display metrics for all initially watched logs (#95)
- Properly add new metrics for all newly found logs (#96)
### Docs

## [v1.8.2] - 2025-11-22
## [1.8.2] - 2025-11-22
### Fixed
- Added missing fields certificatePolicies and ctlPoisonByte (#85)

## [v1.8.1] - 2025-05-04
## [1.8.1] - 2025-05-04
### Fixed
- No longer reject URLs with trailing slashes defined in the `additional_logs` config (#62)
- When using `drop_old_logs` in the config, the server won't remove logs defined in `additional_logs` anymore (#64)

## [v1.8.0] - 2025-05-03
## [1.8.0] - 2025-05-03
### Security
- Close several CVEs in x/crypto and x/net dependencies (#59)

Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ RUN adduser \

# Copy our static executable.
COPY certstream-server-go /app/certstream-server-go
COPY ./config.sample.yaml /app/config.yaml
COPY ./config.docker.yaml /app/config/config.yaml
RUN chown -R certstreamserver:certstreamserver /app/

# Use an unprivileged user.
USER certstreamserver:certstreamserver

EXPOSE 8080

ENTRYPOINT ["/app/certstream-server-go"]
ENTRYPOINT ["/app/certstream-server-go", "-config", "/app/config/config.yaml"]
4 changes: 2 additions & 2 deletions Dockerfile_multistage
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ COPY --from=builder /etc/group /etc/group

# Copy our static executable.
COPY --from=builder /go/bin/certstream-server-go /app/certstream-server-go
COPY --chown=certstreamserver:certstreamserver ./config.sample.yaml /app/config.yaml
COPY --chown=certstreamserver:certstreamserver ./config.docker.yaml /app/config/config.yaml

# Use an unprivileged user.
USER certstreamserver:certstreamserver

EXPOSE 8080

ENTRYPOINT ["/app/certstream-server-go"]
ENTRYPOINT ["/app/certstream-server-go", "-config", "/app/config/config.yaml"]
70 changes: 70 additions & 0 deletions cmd/certstream-server-go/createIndex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"fmt"
"log"
"os"
"path/filepath"

"github.com/spf13/cobra"

"github.com/d-Rickyy-b/certstream-server-go/internal/certstream"
"github.com/d-Rickyy-b/certstream-server-go/internal/config"
)

// createIndexCmd represents the createIndex command
var createIndexCmd = &cobra.Command{
Use: "create-index",
Short: "Create the ct_index.json based on current STHs/Checkpoints",
Long: `When using the recovery feature, certstream will store an index of the processed certificates for each CT log.
create-index will create and pre fill the ct-index.json file with the current values of the most recent certificate for each CT log.`,

RunE: func(cmd *cobra.Command, args []string) error {
configPath, err := cmd.Flags().GetString("config")
if err != nil {
return err
}

conf, readConfErr := config.ReadConfig(configPath)
if readConfErr != nil {
return readConfErr
}
cs := certstream.NewRawCertstream(conf)

force, err := cmd.Flags().GetBool("force")
if err != nil {
return err
}

outFilePath, err := cmd.Flags().GetString("out")
if err != nil {
return err
}

// Check if outfile already exists
outFileAbsPath, err := filepath.Abs(outFilePath)
if err != nil {
return err
}
if _, statErr := os.Stat(outFileAbsPath); statErr == nil {
if !force {
fmt.Printf("Output file '%s' already exists. Use --force to override it.\n", outFileAbsPath)
os.Exit(1)
}
}

createErr := cs.CreateIndexFile(outFilePath)
if createErr != nil {
log.Fatalf("Error while creating index file: %v", createErr)
}

return nil
},
}

func init() {
rootCmd.AddCommand(createIndexCmd)

createIndexCmd.Flags().StringP("out", "o", "ct_index.json", "Path to the index file to create")
createIndexCmd.Flags().BoolP("force", "f", false, "Whether to override the index file if it already exists")
}
41 changes: 1 addition & 40 deletions cmd/certstream-server-go/main.go
Original file line number Diff line number Diff line change
@@ -1,50 +1,11 @@
package main

import (
"flag"
"fmt"
"log"

"github.com/d-Rickyy-b/certstream-server-go/internal/certstream"
"github.com/d-Rickyy-b/certstream-server-go/internal/config"
)

// main is the entry point for the application.
func main() {
configFile := flag.String("config", "config.yml", "path to the config file")
versionFlag := flag.Bool("version", false, "Print the version and exit")
createIndexFile := flag.Bool("create-index-file", false, "Create the ct_index.json based on current STHs")
flag.Parse()

if *versionFlag {
fmt.Printf("certstream-server-go v%s\n", config.Version)
return
}

log.SetFlags(log.LstdFlags | log.Lshortfile)

// If the user only wants to create the index file, we don't need to start the server
if *createIndexFile {
conf, readConfErr := config.ReadConfig(*configFile)
if readConfErr != nil {
log.Fatalf("Error while reading config: %v", readConfErr)
}
cs := certstream.NewRawCertstream(conf)

createErr := cs.CreateIndexFile()
if createErr != nil {
log.Fatalf("Error while creating index file: %v", createErr)
}

return
}

log.Printf("Starting certstream-server-go v%s\n", config.Version)

cs, err := certstream.NewCertstreamFromConfigFile(*configFile)
if err != nil {
log.Fatalf("Error while creating certstream server: %v", err)
}

cs.Start()
Execute()
}
66 changes: 66 additions & 0 deletions cmd/certstream-server-go/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"fmt"
"log"
"os"

"github.com/spf13/cobra"

"github.com/d-Rickyy-b/certstream-server-go/internal/certstream"
"github.com/d-Rickyy-b/certstream-server-go/internal/config"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "certstream-server-go",
Short: "A drop-in replacement for the certstream server by Calidog",
Long: `This tool aggregates, parses, and streams certificate data from multiple
certificate transparency logs via websocket connections to connected clients.`,

RunE: func(cmd *cobra.Command, args []string) error {
// Handle --version flag
versionBool, err := cmd.Flags().GetBool("version")
if err != nil {
return err
}
if versionBool {
fmt.Printf("certstream-server-go v%s\n", config.Version)
return nil
}

// Handle --config flag
configPath, err := cmd.Flags().GetString("config")
if err != nil {
return err
}
// Check if path exists and is a file
_, statErr := os.Stat(configPath)
if os.IsNotExist(statErr) {
return fmt.Errorf("config file '%s' does not exist", configPath)
}

cs, err := certstream.NewCertstreamFromConfigFile(configPath)
if err != nil {
log.Fatalf("Error while creating certstream server: %v", err)
}

cs.Start()

return nil
},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}

func init() {
rootCmd.PersistentFlags().StringP("config", "c", "config.yml", "Path to the config file")
rootCmd.Flags().BoolP("version", "v", false, "Print the version and exit")
}
51 changes: 51 additions & 0 deletions cmd/certstream-server-go/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"fmt"
"log"
"os"

"github.com/spf13/cobra"

"github.com/d-Rickyy-b/certstream-server-go/internal/config"
)

// validateCmd represents the validate command
var validateCmd = &cobra.Command{
Use: "validate",
Short: "Tests whether the config file is valid",
Long: `Validates a configuration file, then exits.

This command deserializes the config and checks for errors.`,
PreRunE: func(cmd *cobra.Command, args []string) error {
// Check if config file exists
configPath, err := cmd.Flags().GetString("config")
if err != nil {
return err
}
// Check if path exists and is a file
_, statErr := os.Stat(configPath)
if os.IsNotExist(statErr) {
return fmt.Errorf("config file '%s' does not exist", configPath)
}

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
configPath, err := cmd.Flags().GetString("config")
if err != nil {
return err
}

readConfErr := config.ValidateConfig(configPath)
if readConfErr != nil {
log.Fatalln(readConfErr)
}
log.Println("Config file is valid!")
return nil
},
}

func init() {
rootCmd.AddCommand(validateCmd)
}
Loading
Loading