Skip to content

chore: add live-credential smoke test across github/gitlab/gitea before merging push/pull/delete changes #57

Description

@ClaudiaFang

Context

Real-provider testing has already caught provider/API behavior that mocked requestUrl cannot reliably cover. The repository supports GitHub, GitLab, and Gitea, so this issue remains the foundation for headless real-provider integration testing.

Previous E2E infrastructure also exposed an important constraint: Node-only test harness code (fetch, globalThis, node:crypto, node:child_process, node:util) can be picked up by the Obsidian scanner even though it is test-only. The revised design keeps those responsibilities out of the plugin TypeScript test surface.

Goal

Run production provider code against real GitHub / GitLab / Gitea repositories with isolated test branches, independent remote verification, and cleanup that remains safe under concurrency and cancellation.

flowchart LR
    CI[GitHub Actions] --> P[Shell harness: provision]
    P --> R[(Dedicated test repo)]
    CI --> T[TypeScript integration tests]
    T --> S[Production provider service]
    S --> R
    R --> V[Shell harness: independent verify]
    V --> C[Shell harness: cleanup]
Loading

Responsibility boundary

Shell / CI harness

Use Shell + standard Git CLI for test-environment work:

  • clone/fetch the dedicated test repository;
  • create an isolated branch for each run;
  • seed initial Git state;
  • independently verify branch/tree/content/commit state;
  • delete the current test branch;
  • garbage-collect stale test branches.

Use gh / glab only when provider-specific API behavior cannot be expressed cleanly with standard Git. Keep Docker/service startup for Gitea at the GitHub Actions layer rather than spawning it from Node.

Do not reintroduce Node-only provisioning/verifier scripts into the plugin E2E suite.

TypeScript integration tests

TypeScript tests should only exercise the code under test:

  • instantiate the real production provider service;
  • testConnection;
  • list/read/push/update/delete;
  • batch operations;
  • move/rename semantics;
  • conflict/concurrency protections;
  • root-path handling and provider-specific behavior.

Independent verification must not reuse the provider implementation under test.

Git authentication

CI secrets should be injected as job-scoped environment variables and exposed to Git through GIT_ASKPASS.

Do not:

  • embed tokens in remote URLs;
  • persist tokens into .git/config;
  • pass tokens as normal CLI arguments;
  • print tokens in logs or artifacts.

The askpass helper contains no credential itself; it only reads the job-scoped environment value when Git requests authentication.

Branch isolation

Every provider job receives a unique remote branch. A cancelled/stuck run must never share state with a newer run.

PR run:

e2e/pr/123/github/run-987654-1

Branch-only run:

e2e/branch/feat-settings-compat-a31f2c/github/run-987654-1

Identity should include:

  • PR number, or sanitized source-branch name + short hash;
  • provider;
  • github.run_id;
  • github.run_attempt.

Cleanup lifecycle

Cleanup is best-effort; correctness must not depend on cleanup always running.

  1. Per-job cleanup

    • if: always();
    • delete only the current run branch.
  2. PR / source-branch lifecycle cleanup

    • PR closed/merged → remove e2e/pr/<number>/**;
    • source branch deleted → remove its e2e/branch/<name>/** namespace.
  3. Scheduled janitor

    • periodically remove stale e2e/** branches older than a TTL;
    • covers runner crash, force cancellation, network failure, or failed cleanup.

A new run always allocates a new branch, so an orphan from an older run is harmless until the janitor removes it.

CI shape

Keep provider and Obsidian compatibility matrices independent. This issue owns the provider matrix only:

provider / GitHub
provider / GitLab
provider / Gitea

Each provider job follows the same lifecycle:

provision -> seed -> TypeScript integration -> independent verify -> cleanup

Do not create an Obsidian-version × provider Cartesian matrix.

Provider contract coverage

Shared scenarios

  • testConnection
  • pushFile create/update
  • getFile
  • pushBatch
  • deleteFile
  • deleteBatch
  • listFilesDetailed
  • getBlob
  • root-path handling
  • move/rename verification
  • conflict/concurrency safety

GitHub additional scenarios

  • GraphQL batch commit verification
  • GraphQL errors[] handling
  • symlink push (mode 120000)

Acceptance criteria

  • GitHub / GitLab / Gitea real-provider jobs run independently in CI.
  • Provision / verify / cleanup use Shell + Git CLI rather than Node-only E2E infrastructure.
  • Production TypeScript provider code is the code under test.
  • Independent verification does not reuse the provider implementation.
  • Every run has an isolated remote branch.
  • Concurrent/cancelled runs cannot overwrite one another.
  • PR close/merge and source-branch deletion clean their test namespaces.
  • Scheduled janitor removes orphaned branches.
  • Tokens never appear in remote URLs, Git config, command arguments, logs, or artifacts.
  • Obsidian scanner remains clean with the real-provider test infrastructure present.

Follow-up

GUI/real-Obsidian automation remains tracked separately in #115 and should reuse this provider sandbox/lifecycle rather than duplicate it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions