rickub/clipublic Fork
⑂ main
Commits
⬇ Clone ▾
git clone https://git.rickub.com/rickub/cli.git
git clone ssh://git@rickub.com/rickub/cli.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

run logs: --job and --failed, so one red job is not six jobs of noise (#8) #2

Merged@ogirardot wants to merge feat/8-run-logs-job-filter into main
Merged as 1f3fca34d9b6.
  • @ogirardot opened this merge request · Sep 7, 2026

    Closes #8.

    run logs <n> printed the whole run's interleaved output. A rickub CI run has six
    jobs, so triaging one red job meant pulling a multi-megabyte log to read ~5 lines
    — and the cost of not triaging is worse: it trains reviewers to blind-re-run red
    MRs, which is how a real failure eventually gets waved through.

    The information was already there — the API returns logs per job, with a name and
    a status — so this is pure client-side selection.

    What's new

    rickub run logs 30 --job ssh        # one job
    rickub run logs 30 --failed         # every job whose status is not success
    rickub run logs 30 --job ssh --json # the filter applies to --json too
    
    • --job matches case-insensitively: job names come from workflow YAML, and
      SSH vs ssh is a typo worth forgiving rather than reporting.
    • --failed is deliberately wider than "failure" — a cancelled job is also not
      green, and "what isn't green?" is the actual question ~90% of the time.
    • The filter runs before the --json branch, so --job X --json cannot
      silently return the whole run.

    The part that matters

    An unknown --job is an error listing the run's real job names, never a
    fall-through to everything:

    $ rickub run logs 30 --job web
    rickub: no job named "web"; this run has: vet / vuln / gosec / staticcheck / modules
    

    A typo that returned the full log would look like it worked — and a filter you
    cannot trust is worse than no filter, because you stop believing the short output
    and re-run without it, which is exactly the cost the flag was added to remove. An
    empty --failed result says Every job succeeded — nothing to show. rather than
    ending on silence, for the same reason.

    --job together with --failed is refused: intersecting them prints nothing
    whenever the named job passed, which is indistinguishable from the typo case.

    The no-flag behaviour is unchanged, and a test pins that.

    Verified

    Against this repo's real runs, not only in tests: --job on a real name, the
    case-insensitive form, the unknown-name error above, the both-flags refusal, an
    empty --failed on a green run, and --failed --json.

    🤖 Generated with Claude Code

    https://claude.ai/code/session_01KPPhRdTiUiiSvLjthotkT1

  • @ogirardot · Sep 7, 2026

    Reviewed at effort high; four findings, two medium and two low. All four are
    fixed in the follow-up commit — the two mediums were real holes in the flag's own
    contract.

    1. An empty --job disabled the filter (medium). The guard tested
    runLogsJob != "", so rickub run logs 30 --job "$JOB" with JOB unset printed
    all six jobs and exited 0 — exactly the "a typo that quietly printed the whole log
    would look like it worked" failure the flag was added to prevent, arriving through
    the shell instead of through a typo. It also defeated the mutual exclusion:
    --job "" --failed was accepted and silently behaved as --failed. The decision
    now keys on cmd.Flags().Changed("job"), and an empty name is refused with the
    run's job list.

    2. A jobless run was told "Every job succeeded" (medium). The empty-result
    message branched on runLogsFailed, but logs.Jobs had already been overwritten
    by the filter, so len(logs.Jobs) == 0 could not distinguish "all green" from
    "this run never produced a job". A run that failed before any job started — bad
    workflow YAML, a dispatch error — was reported as all-green, which is the same
    class of lie the rest of this MR is arguing against. It branches on the pre-filter
    count now.

    3. Server-controlled job names reached the terminal unsanitized (low). In the
    job header, and more importantly in the unknown-job error: that one goes out
    through main's bare fmt.Fprintf(os.Stderr, "rickub: %s\n", err), which applies
    no cleaning of its own. Every other human-facing server string in this codebase is
    clean()ed per b7e1d1f; a job named with an erase-line sequence could otherwise
    repaint or hide lines for anyone inspecting that repo's runs. Both are cleaned now,
    with a test that asserts the escape does not survive while the readable remainder
    of the name is still listed.

    4. --job returned only the first name match (low). A matrix leg or a
    workflow called twice can emit two jobs sharing a name; one of them vanished with
    no indication. That is the short-output-you-cannot-trust outcome the function's own
    doc comment argues against. It returns every match.

    Each fix has a regression test. Verified live as well: an unset --job variable
    and --job "" --failed both now exit non-zero instead of printing everything.

Sign in to comment.