Skip to content

Begin Handshake CLI checkpoint - #4

Draft
isomorphisms wants to merge 22 commits into
clifrom
handshake-cli
Draft

isomorphisms wants to merge 22 commits into
clifrom
handshake-cli

Conversation

@isomorphisms

@isomorphisms isomorphisms commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Purpose

Start a small read-only Handshake command-line client in Idriç without confusing Handshake's authenticated web application with its documented APIs.

The first analytical target is the relationship between a job posting and Handshake's attached job-role-group classification, so the first two EDU API resources remain separate raw tables keyed by job_id:

  • /jobs
  • /job_role_groups

The public job-detail URL is exposed separately and is not treated as the EDU API.

Surface reconciliation

The original draft named seven holes. Current Idriç supplies six directly or with small client-local logic: string cleanup, file input, structural contrib JSON, System.getEnv, and decimal validation are all implemented.

The seventh was the real transport gap. That stack is now explicit:

  • ICU #12: file-backed response capture;
  • ICU #13: checked caller-supplied request headers plus fetch_to_files_with_headers;
  • ICU #20 / issue #19: make_credential_header, preserving a caller-declared credential on same-origin redirects and stripping it when scheme, host, or port changes.

Handshake now uses that surface. edu_icu_get parses the URL, constructs x-api-key with make_credential_header, calls fetch_to_files_with_headers, reads the captured body, cleans its temporary files, and treats nonzero ICU transport results as failures. It does not echo the key in diagnostics.

No curl, Python, browser-cookie replay, or Handshake-specific socket path is used by the client.

JSON boundary

Current Idriç already ships Language.JSON in contrib, so this PR carries no private JSON grammar. Only fields needed for the two raw output tables are decoded into Handshake records; unrelated fields remain parsed JSON and are ignored.

Language.JSON represents JSON numbers as Double. Required identifier fields are accepted only when the parsed number converts back to the same integral value. If Handshake emits identifiers outside that exactly representable range, that remains an explicit decoder limitation.

Synthetic fixtures only; no private payloads are committed.

Credential redirect acceptance

The Handshake checkpoint now builds the current ICU credential-header stack and runs the real Handshake executable against two deterministic local HTTP origins.

The first origin requires synthetic x-api-key on the initial request and again after a same-origin redirect. It then redirects to a second origin. The second origin rejects the request if x-api-key is present and returns the committed jobs fixture only when the credential has been stripped.

That cross-repository receipt complements ICU #20's own native test, which also proves unrelated custom headers survive while Authorization, Cookie, and caller-declared credentials are removed cross-origin.

Commands

handshake url jobs
handshake url roles
handshake public JOB_ID
handshake fixture-jobs FILE
handshake fixture-roles FILE
handshake jobs
handshake roles

jobs and roles require HANDSHAKE_EDU_API_KEY; missing and empty keys remain separate refusal cases. HANDSHAKE_EDU_BASE_URL exists for deterministic transport acceptance while the url commands continue to print Handshake's documented production endpoints.

Intentional limits

  • one page only; cursor pagination follows after a single authorized live page works;
  • no join yet: raw /jobs and /job_role_groups observations stay separate;
  • no authenticated student-site scraping;
  • no browser-cookie replay;
  • no hidden fallback transport;
  • no claim that a public job-detail URL implies a stable machine-readable public jobs API.

This PR remains draft while the ICU #13/#20 stack is pending; the client no longer has an application-level fail-closed stub for #19.

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