Skip to content

[bug-hunter] fetch-workflow-logs --since misfilters timezone-offset ISO8601 values #2158

Closed as not planned

Description

@github-actions

Impact

Users running scripts/fetch-workflow-logs.py with a valid ISO 8601 --since value that includes a timezone offset can receive incorrect workflow runs (older runs included as if they were newer). This can skew failure triage and log analysis.

Reproduction Steps

  1. Create and run this new minimal script:
import importlib.util
from pathlib import Path

script_path = Path('scripts/fetch-workflow-logs.py')
spec = importlib.util.spec_from_file_location('fetch_workflow_logs', script_path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

def fake_github_api(path, token, accept='application/vnd.github+json'):
    if path.endswith('page=1'):
        return b'{"workflow_runs":[{"id":1,"created_at":"2025-01-01T04:30:00Z","conclusion":"failure"}]}'
    return b'{"workflow_runs":[]}'

mod.github_api = fake_github_api
runs = mod.list_workflow_runs(
    repo='elastic/ai-github-actions',
    workflow='ci.yml',
    token='x',
    since='2025-01-01T00:00:00-05:00',
    until=None,
    conclusion='failure',
    last=20,
)

# Expected no runs: 04:30Z is before 05:00Z
assert runs == [], f'Expected [], got {[r["id"] for r in runs]} with created_at={[r.get("created_at") for r in runs]}'
  1. Run:
python /tmp/gh-aw/agent/repro_fetch_since_tz_failing.py

Expected vs Actual

Expected: No runs are returned, because 2025-01-01T04:30:00Z is earlier than 2025-01-01T00:00:00-05:00 (2025-01-01T05:00:00Z).

Actual: The run is included, and the script fails with:

Traceback (most recent call last):
  File "/tmp/gh-aw/agent/repro_fetch_since_tz_failing.py", line 26, in <module>
    assert runs == [], f'Expected [], got {[r["id"] for r in runs]} with created_at={[r.get("created_at") for r in runs]}'
AssertionError: Expected [], got [1] with created_at=['2025-01-01T04:30:00Z']

Failing Test

import importlib.util
from pathlib import Path

script_path = Path('scripts/fetch-workflow-logs.py')
spec = importlib.util.spec_from_file_location('fetch_workflow_logs', script_path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

def fake_github_api(path, token, accept='application/vnd.github+json'):
    if path.endswith('page=1'):
        return b'{"workflow_runs":[{"id":1,"created_at":"2025-01-01T04:30:00Z","conclusion":"failure"}]}'
    return b'{"workflow_runs":[]}'

mod.github_api = fake_github_api
runs = mod.list_workflow_runs(
    repo='elastic/ai-github-actions',
    workflow='ci.yml',
    token='x',
    since='2025-01-01T00:00:00-05:00',
    until=None,
    conclusion='failure',
    last=20,
)

assert runs == [], f'Expected [], got {[r["id"] for r in runs]} with created_at={[r.get("created_at") for r in runs]}'

Evidence

  • scripts/fetch-workflow-logs.py:71-75 compares timestamps as raw strings:
    • _is_before_since_boundary returns run.get("created_at", "") < since
  • scripts/fetch-workflow-logs.py:89-92 uses that boundary check to stop pagination.
  • With timezone offsets, lexical string comparison is not equivalent to chronological comparison.

What is this? | From workflow: Trigger Bug Hunter

Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.

  • expires on Sep 30, 2026, 11:26 AM UTC

Activity

  1. github-actions commented on Sep 30, 2026

    @github-actions
    ContributorAuthor

    This issue was automatically closed because it expired on 2026-09-30T11:26:45.535Z.

    Closed by Workflow

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions