Commits on Source 6

  • Matt Cockayne's avatar
    docs: say that the transport rungs are not consumed yet · 6f9fd495
    Matt Cockayne authored
    forge.WithHTTPTransport and forge.WithHTTPClient record what they are given and
    no first-party adapter reads it back. Every adapter's factory takes
    opts ...forge.Option and consults exactly one thing, Options.Logger, before
    calling NewReleaseProvider — and no adapter's Settings has a field for the value
    to reach.
    
    The documentation said otherwise. The configuration reference listed both rungs
    as working options, the authoring guide told provider authors what to do with
    them, and the reuse-a-connection guide opened with transport sharing as "the
    cheapest change, and the one to make first" over a copy-pasteable example. A
    consumer following that example gets no effect, no error, and no way to find out.
    
    That is worse than the rung not existing, and it is documentation rather than
    code that made it so — the audit recorded in spec 0008's revision log found the
    gap, and this closes the half that misleads.
    
      - godoc on both options and on the package block says NOT YET CONSUMED, and
        points at forge/pool, which reuses the whole provider and works today;
      - reuse-a-connection leads with the pool and demotes the transport rung to a
        section that says plainly it does nothing yet;
      - the configuration reference carries the same warning beside the table;
      - the authoring guide keeps the instruction — it is the contract a new
        provider should honour — and adds that none of the first-party four do,
        with the warning that a partial adoption is worse than none. forge-github
        builds a client in three places, one of them the asset download, so a
        provider honouring the injection on its API client alone would hand a caller
        a pool that quietly does not cover every request.
    
    Four stale claims found while reading, all predating this change and all now
    describing a codebase that no longer exists:
    
      - reuse-a-connection said the module "does not yet surface errors that assert
        credential-invalidity", so Invalidate could not be used from a provider's
        error. forge.ErrUnauthorized shipped in v0.13.0 and is exactly that signal.
        Replaced with the example, and with which two sentinels must NOT trigger it.
      - backend-agnosticism repeated the "ErrReleaseNotFound is not yet uniform"
        claim already corrected in the errors reference. It is uniform, and the
        conformance harness enforces it; what varies is which sentinel a bare 404
        carries, which is a provider decision (0009 D4).
      - limitations and the providers reference both documented
        ReleaseSource.Private as a construction-time fast failure. The field went
        with ReleaseSourceConfig (0008 D3) and the check it fed moved to the
        operation (D8), because whether a repository is private is not knowable at
        construction.
    
    No code changes beyond doc comments.
    6f9fd495
  • Matt Cockayne's avatar
    docs: name the credential leaks the platform SDKs make reachable · 8ca83a8b
    Matt Cockayne authored
    Two of the three first-party SDKs offer a method that leaks a credential when
    used exactly as its name suggests. Both were verified by request against the
    versions this module pins, not by reading the source.
    
    go-gitlab v2.58.0. NewRequestToURL attaches PRIVATE-TOKEN to a request for any
    URL and refuses a URL off the client's base host, which reads as a guardrail. It
    is not one: the check runs when the request is BUILT, and the client then follows
    a redirect off-host carrying the credential. An instance asset link redirecting
    to object storage is GitLab's ordinary path for a large file, so the correct
    looking use of the SDK's own arbitrary-URL method sends the token wherever a
    release author's link resolves.
    
    go-github v90.0.0. Client() returns the underlying *http.Client, whose every
    request carries Authorization: Bearer <token> to any host. The only protection is
    its doc comment. Its download path is correct by contrast, and is documented here
    as the shape to copy: bareDoUntilFound stops at the redirect, then refetches with
    a fresh credential-free request through a caller-supplied client.
    
    gitea.dev/sdk v1.2.0 exposes no client accessor, no token accessor and no
    arbitrary-URL request method, so there is nothing to misuse.
    
    The reason this is documentation rather than a code change is that forge is
    already safe: forge-gitlab builds its download client with
    httpclient.WithSensitiveHeaders("PRIVATE-TOKEN"), whose CheckRedirect deletes the
    header on any cross-host hop, and TestDownloadReleaseAsset_TokenNotForwardedAcrossRedirect
    pins it. What was missing was any record of WHY that is load-bearing — so the
    next person to reach for the SDK's tidier-looking path knows what it costs.
    
    Recorded in spec 0008's D5 revision as the finding that settled the rung, and
    rejected there as a simplification: routing forge-gitlab's download through
    NewRequestToURL would have been a security regression.
    8ca83a8b
  • Matt Cockayne's avatar
    docs: the connection rungs are consumed, and rung 1 exists · b47ecc02
    Matt Cockayne authored
    Spec 0008 D4 and D5 are built. The documentation said the transport rungs were
    recorded and read by nothing, which was true when it was written and is not now:
    all four adapters honour both options for their own API requests, and
    forge-github, forge-gitlab and forge-gitea offer NewProviderFromClient.
    
    What replaces the warning is the part a caller still needs to know, because it is
    a deliberate limit rather than a gap: no adapter uses a supplied CLIENT to fetch
    a release asset. That URL comes from author-controlled metadata, and whether a
    credential can leave the pinned host is decided by the fetching client's redirect
    behaviour. A supplied client carries the caller's policy, and may carry the
    caller's credentials in headers the standard library does not know to strip — it
    protects Authorization, Cookie and WWW-Authenticate on a cross-host redirect and
    nothing else. An adapter cannot inspect a client to find out, so it builds its
    own for that hop. A supplied transport is used everywhere, so the pooling benefit
    is complete either way.
    
    reuse-a-connection gains a section for rung 1, including the consequence that
    differs by forge: downloads stay authenticated on GitHub, because go-github's
    download rides the SDK client and follows the redirect credential-free, and go
    anonymous on GitLab and Gitea, where an asset is an author-supplied URL the SDK
    never fetches and neither SDK exposes its credential. A private asset therefore
    resolves on one and fails on the other two, which is a property of the rung
    rather than a defect, and the escape is a lower rung.
    
    direct gains the documented absence D5 requires: it has no platform SDK, so its
    native unit is the *http.Client and a rung taking one would duplicate
    WithHTTPClient.
    b47ecc02
  • Matt Cockayne's avatar
    docs: correct fifteen claims that no longer match the code · 7c0709d6
    Matt Cockayne authored
    A documentation audit against the source, run because six drift findings had
    already surfaced by accident during two specs' implementation. It found eleven
    more, plus a stale index; sweeping for the same shapes afterwards found three
    the audit missed.
    
    Snippets that do not compile, which is the worst of it because a reader copies
    them:
    
      - README.md and two snippets in migrate-from-resolvetoken referenced `src`
        inside a closure whose parameter is `ep forge.Endpoint` — the name of the
        type the Endpoint cut replaced, so they read as the old API throughout.
      - author-a-provider built a Settings literal with a ReleaseSource field that
        does not exist; the field is Endpoint.
      - logging.md carried the same `src` in two more factory calls.
    
    migrate-from-resolvetoken additionally taught the anti-pattern its own next
    section forbids: it passed forge.SubConfig(cfg, "github") into
    SettingsFromConfig, four lines above the paragraph explaining that doing so makes
    the adapter look for github.github.auth.value and quietly find nothing. That
    function's own doc comment calls it "the second-most-common mistake".
    
    Claims that were true when written and are not now:
    
      - limitations said ErrReleaseNotFound is not uniform and not to be relied on.
        It is uniform, and the conformance harness enforces it. What varies is which
        not-found sentinel a bare 404 carries, which is a provider decision.
      - configuration documented ReleaseSourceConfig.Private as a bitbucket
        construction-time fast failure. The field went with the type in 0008 D3, and
        the check moved to the operation in D8.
      - getting-started said WithLogger is the only option. There are three.
      - providers referenced ReleaseSource.Host in four places and pinned
        go-github/v89; the module is on v90.
      - direct-provider documented the {tool} default as ReleaseSource.Repo; it is
        the literal string "tool".
      - testing listed eleven mocks; there are twelve, and MockSnippets was missing
        from the table.
      - conformance-harness said sixteen checks against a seventeen-row table. The
        count was wrong before this cycle and my own edit adding two checks carried
        the error forward rather than fixing it.
    
    The specs index gains 0009, which shipped code has been citing since v0.14.0.
    
    Docs only; no behaviour change.
    7c0709d6
  • Matt Cockayne's avatar
  • Matt Cockayne's avatar
    chore(main): release v0.14.1 · 17bd3a6f
    Matt Cockayne authored
    17bd3a6f
Loading
Loading