Skip to content

[TT-17817] Keeping Tyk Dependencies Up To Date - Building The Alerting and Update Mechanism - #148

Open
buraksezer wants to merge 6 commits into
mainfrom
feat/TT-17817/eol-notifier
Open

[TT-17817] Keeping Tyk Dependencies Up To Date - Building The Alerting and Update Mechanism#148
buraksezer wants to merge 6 commits into
mainfrom
feat/TT-17817/eol-notifier

Conversation

@buraksezer

@buraksezer buraksezer commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

PR for https://tyktech.atlassian.net/browse/TT-17817

A scheduled job that reads the endoflife.date API and
posts one Slack message to a configured channel.

It sends two kinds of alert:

  • A tracked version is exactly 12, 6 or 1 month away from the end of a support phase.
  • The API lists a version that the last run did not see.

This tool only sends alerts. Adding or removing a version from a test matrix
still needs a manual PR.

How it works

Daily at 07:00 UTC, or by hand with workflow_dispatch:

  1. Restore state.json from the eol-notifier-state branch.
  2. Read and check the config. A bad config fails the run before any request.
  3. Fetch each product once. 13 dependencies map to 10 slugs, so 10 requests. It retries once on a 5xx or a timeout.
  4. Compare the dates against the thresholds, and the version list against the state.
  5. Post one message. Nothing to report means no message.
  6. Commit state.json back, but only if it changed.

State management

To find a new version, the job needs to know what the last run saw. It keeps a
state.json that maps each product slug to the versions the API listed.

  • It lives on its own branch, because main needs a reviewed PR and the job cannot push there.
  • It is written only after Slack accepts the message. A version is never marked as seen if its alert did not go out.
  • A product with no state is a baseline: the job records what it sees and sends nothing. This covers the first run and any dependency added later, so the channel does not get a list of old versions.
  • A failed fetch leaves that product's record alone, so its versions are not announced twice later.
  • End-of-life alerts do not use the state at all.

Notes for reviewers

  • EoL alerts go out on one exact day, as the policy requires. A run that is skipped or fails loses that day's alert. The next threshold still fires.
  • HashiCorp sets an end-of-life date on the day support ends, not before. So Vault and Consul never trigger the 12, 6 or 1 month alerts. The job reports their new versions instead. The docs explain why.
  • upstream_proxy covers GCP MemoryStore, GCP Cloud SQL and Azure DocumentDB, which endoflife.date does not track. They follow the upstream engine, and the message says the date must be confirmed with the provider.

@TykTechnologies TykTechnologies deleted a comment from probelabs Bot Aug 12, 2026
@TykTechnologies TykTechnologies deleted a comment from probelabs Bot Aug 12, 2026
@buraksezer
buraksezer marked this pull request as ready for review August 12, 2026 13:32
@buraksezer
buraksezer requested a review from a team August 12, 2026 13:32
@probelabs

probelabs Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

This PR introduces a new, scheduled GitHub Action, "Dependency EoL Notifier," designed to proactively monitor dependency end-of-life (EoL) dates. It queries the endoflife.date API and sends consolidated alerts to a configured Slack channel, helping to ensure all dependencies remain up-to-date and supported.

The notifier is a self-contained Go application packaged as a composite GitHub Action. It runs daily and checks for two types of events:

  1. Approaching EoL: Triggers when a tracked dependency's support phase is exactly 12, 6, or 1 month away.
  2. New Versions: Triggers when the API lists a new version of a dependency not seen in the previous run.

To manage state, the action uses a state.json file stored on a separate eol-notifier-state branch. This approach avoids automated commits to the main branch and ensures state is only updated after a successful Slack notification.

Files Changed Analysis

This PR is entirely additive, introducing 26 new files and over 3,700 lines of code to create the eol-notifier tool. The changes are well-isolated and do not modify existing functionality.

  • New GitHub Action (eol-notifier/): The core of the PR is a new Go application that serves as a composite GitHub Action. It includes the main application logic, configuration handling, an API client for endoflife.date, state management, and Slack message formatting, all accompanied by a comprehensive suite of unit tests.
  • New Workflow (.github/workflows/eol-notifier.yaml): A new workflow schedules the action to run daily. It also manages the checkout and commit of the state file to the dedicated eol-notifier-state branch.
  • Configuration (.github/eol-notifier/dependencies.yaml): A new YAML file allows easy configuration of tracked dependencies, their endoflife.date product slugs, and the specific lifecycle phases to monitor.
  • Documentation (docs/workflows/eol-notifier.md, eol-notifier/README.md): Detailed documentation explains the purpose, configuration, and operation of both the workflow and the action.
  • CI/CD Updates (.github/workflows/ci-test.yml, .github/.dependabot.yml): The CI test workflow and Dependabot configuration have been updated to include the new eol-notifier Go module.

Architecture & Impact Assessment

  • What this PR accomplishes: It automates dependency lifecycle monitoring, providing timely alerts to engineering teams about upcoming EoL dates and new releases. This facilitates proactive upgrade planning and helps maintain a secure, supported software stack.

  • Key technical changes introduced:

    • A new scheduled, stateful GitHub workflow for proactive monitoring.
    • A robust Go-based composite action containing the core logic.
    • An effective state management strategy using a dedicated Git branch, which isolates automated commits from the main development branch.
    • Integration with the external endoflife.date API and Slack for notifications.
  • Affected system components: This is a net-new addition to the repository's CI/CD and developer tooling. It has no direct impact on production application code but introduces a new automated process for dependency management.

System Flow

sequenceDiagram
    participant GHA as GitHub Actions Runner
    participant Git
    participant EoL Notifier as eol-notifier Action
    participant EoL API as endoflife.date API
    participant Slack

    GHA->>Git: Fetch state branch (eol-notifier-state)
    GHA->>EoL Notifier: Execute with config and state.json
    EoL Notifier->>EoL API: Fetch lifecycle data for each product
    EoL API-->>EoL Notifier: Return product releases and dates
    EoL Notifier->>EoL Notifier: Compare with state.json and thresholds
    alt Has Alerts
        EoL Notifier->>Slack: Post formatted digest message
        Slack-->>EoL Notifier: Acknowledge message
        EoL Notifier->>GHA: Write updated state.json
        GHA->>Git: Commit and push new state to state branch
    else No Alerts
        EoL Notifier->>GHA: Exit without writing state
    end
Loading

Scope Discovery & Context Expansion

The impact of this PR is focused on the repository's developer and operational tooling. It establishes a new, automated process for dependency management that was previously manual.

  • Entrypoint: The process is triggered by the schedule in .github/workflows/eol-notifier.yaml.
  • Configuration: The tool's behavior is defined in .github/eol-notifier/dependencies.yaml, which specifies the set of tracked dependencies.
  • Core Logic: The Go application in eol-notifier/cmd/notifier/ contains all business logic, including data fetching (endoflife.go), alert detection (lifecycle.go), state management (state.go), and notifications (slack.go).
  • State Persistence: The use of the eol-notifier-state branch is a key architectural decision for managing state without requiring PRs for automated changes. The git operations are handled directly in the workflow file.
  • Testing: The feature is well-tested with unit tests covering configuration, date calculations, alert detection, and message generation, ensuring its reliability.
Metadata
  • Review Effort: 4 / 5
  • Primary Label: feature

Powered by Visor from Probelabs

Last updated: 2026-08-13T08:34:45.136Z | Triggered by: pr_updated | Commit: ed51f92

💡 TIP: You can chat with Visor using /visor ask <your question>

@probelabs

probelabs Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Architecture Issues (1)

Severity Location Issue
🟡 Warning eol-notifier/cmd/notifier/config.go:53
The `loadConfig` function uses a function parameter `process` to inject the `envconfig.Process` dependency for testing. While this is a valid dependency injection pattern, a simpler approach is available in modern Go using `t.Setenv` to set environment variables directly within tests. This would simplify the signature of `loadConfig` and make the tests slightly more straightforward.
💡 SuggestionRefactor `loadConfig` to call `envconfig.Process` directly and update the corresponding tests in `config_test.go` to use `t.Setenv` for setting up test conditions. This will remove the need for the `process` function parameter, simplifying the function's signature and its usage in `main.go`.
\n\n

Architecture Issues (1)

Severity Location Issue
🟡 Warning eol-notifier/cmd/notifier/config.go:53
The `loadConfig` function uses a function parameter `process` to inject the `envconfig.Process` dependency for testing. While this is a valid dependency injection pattern, a simpler approach is available in modern Go using `t.Setenv` to set environment variables directly within tests. This would simplify the signature of `loadConfig` and make the tests slightly more straightforward.
💡 SuggestionRefactor `loadConfig` to call `envconfig.Process` directly and update the corresponding tests in `config_test.go` to use `t.Setenv` for setting up test conditions. This will remove the need for the `process` function parameter, simplifying the function's signature and its usage in `main.go`.
\n\n ### Performance Issues (2)
Severity Location Issue
🟡 Warning eol-notifier/cmd/notifier/lifecycle.go:146
The `dependenciesFor` function is called within nested loops that iterate over products, their releases, and lifecycle phases. This function iterates over the entire list of dependencies each time it is called, leading to redundant computations. The current algorithmic complexity is suboptimal and will scale poorly as the number of tracked dependencies increases.
💡 SuggestionTo optimize, pre-process the dependency configuration into a map where keys are product names and values are the corresponding dependency configurations. This map can be built once before the loops begin. Inside the loops, use this map for a fast O(1) lookup to retrieve dependencies for the current product, which will significantly improve performance by avoiding repeated iterations over the full dependency list.
🟡 Warning eol-notifier/cmd/notifier/main.go:167
The `fetchProducts` function iterates through the list of product names and fetches their data from the API sequentially. While acceptable for a small number of products, this approach can become a bottleneck if the list of products grows or if the API has high latency, as the total execution time is the sum of all individual API requests.
💡 SuggestionConsider parallelizing the API calls to fetch product data concurrently. By using goroutines and a `sync.WaitGroup`, all network requests can be initiated at once, and the function can wait for all of them to complete. This would reduce the total time for this step to that of the longest single request, improving the overall performance of the action.

Quality Issues (1)

Severity Location Issue
🟡 Warning eol-notifier/cmd/notifier/main.go:204
The `logError` function writes the same formatted error message to both `os.Stdout` and `os.Stderr`. This is redundant and will cause duplicated error messages in the GitHub Actions logs, which can make debugging more difficult. Standard practice for error logging is to write to `os.Stderr` only.
💡 SuggestionRemove the redundant logging to `os.Stdout` to ensure error messages appear only once in the logs. The standard error stream is the correct destination for error messages.
🔧 Suggested Fix
        _, _ = fmt.Fprintln(os.Stderr, line)

Powered by Visor from Probelabs

Last updated: 2026-08-13T08:34:29.128Z | Triggered by: pr_updated | Commit: ed51f92

💡 TIP: You can chat with Visor using /visor ask <your question>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant