Skip to content

feat(client): add the runner API and export the HTTP client as client/http - #33

Draft
grubmeshi wants to merge 7 commits into
mainfrom
feature/single-go-bin-runner
Draft

grubmeshi wants to merge 7 commits into
mainfrom
feature/single-go-bin-runner

Conversation

@grubmeshi

@grubmeshi grubmeshi commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

🤖 Written by AI agent

building-block-runner moves all its runners into one Go binary (meshcloud/building-block-runner#86). It builds its meshStack client through pkg/auth.ResolveClient, as the Terraform provider does, and needs a client it can call from another module.

Reading order

  1. Move. internal/http becomes client/http and internal/version becomes client/types/version, with only the imports rewritten.
  2. client/http API. No exported name of client uses an internal/ type any more, and TestPublicApiNamesNoInternalType checks it. New client options: WithoutRedirects(), and WithRetry(policy), which picks per request which failures are retried. Without options, NewClient returns the shared client as before.
  3. client.Runner. A runner claims a run, registers as a status source, reports status, and downloads or uploads the plan artifact, using the run token. ForRunUuid reports with the runner's own credentials. A run's implementation decodes into one typed variant by its type; the Terraform variant carries async. An INTEGER input keeps every digit as *big.Int. NewRunnerClient builds this API alone.
  4. Comments that pointed into the old runner layout.

Changes for callers of client

  • WithHeader replaces WithAccept and WithHeaders, and WithBody takes the content type.
  • Send returns the raw response, and an Error names the method and URL.
  • The client.Authorization alias is gone; use http.Authorization.
  • ListOptions and Page move to client/types.

Merge order

Merge and release this first. #86 then pins the release in place of this branch's head.

Cross-repo PRs

🤖 Generated with Claude Code

@meshcloud-gh-actions

meshcloud-gh-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Coverage of the acceptance run against the meshStack backend, on 9f1ecade683793ca8fc5a85cf508f6a5201094cc.

Scope Coverage
Unit tests 79.1%
Acceptance tests 58.2%
Combined 81.8%
Uncovered functions
client/api_key.go:18: MeshApiKey.meshObjectId 0.0%
client/api_key_permissions.go:20: ApiKeyPermissions.AllCodes 0.0%
client/api_key_permissions.go:33: ApiKeyPermissions.WorkspaceCodes 0.0%
client/api_key_permissions.go:262: AllApiKeyPermissions 0.0%
client/api_key_permissions.go:266: WorkspacePermissionCodes 0.0%
client/building_block_definition.go:68: MeshBuildingBlockDefinitionApprovalPolicies.NothingRequiresApproval 0.0%
client/building_block_definition.go:79: DisabledSchedule 0.0%
client/building_block_definition.go:86: MeshBuildingBlockDefinitionSchedule.IsDisabled 0.0%
client/building_block_definition.go:90: MeshBuildingBlockDefinitionSpec.HasNeutralPolicies 0.0%
client/building_block_definition.go:94: MeshBuildingBlockDefinitionSpec.WithNeutralPolicies 0.0%
client/building_block_definition.go:149: MeshBuildingBlockDefinition.meshObjectId 0.0%
client/building_block_definition_version.go:97: MeshBuildingBlockType.TagInputTargets 0.0%
client/building_block_definition_version.go:218: MeshBuildingBlockDefinitionVersion.meshObjectId 0.0%
client/building_block_definition_version.go:221: MeshBuildingBlockDefinitionVersion.meshObjectInOwnOrder 0.0%
client/building_block_run.go:139: meshBuildingBlockRunClient.Claim 0.0%
client/building_block_run.go:158: MeshBuildingBlockRun.meshObjectId 0.0%
client/building_block_run_source.go:64: meshBuildingBlockRunClient.RegisterSource 0.0%
client/building_block_run_source.go:73: meshBuildingBlockRunClient.UpdateSourceSteps 0.0%
client/building_block_run_source.go:78: meshBuildingBlockRunClient.DownloadArtifact 0.0%
client/building_block_run_source.go:87: meshBuildingBlockRunClient.UploadArtifact 0.0%
client/building_block_run_source.go:98: *cappedWriter.Write 0.0%
client/building_block_runner.go:64: MeshBuildingBlockRunner.meshObjectId 0.0%
client/building_block_v2.go:237: *MeshBuildingBlockV2.IsWaitingForInput 0.0%
client/building_block_v2.go:256: *MeshBuildingBlockV2.DeletionSuccessful 0.0%
client/building_block_v2.go:277: MeshBuildingBlockV2.meshObjectId 0.0%
... and 67 more

covdata func names a method without its receiver, so an entry can belong to an implementation nothing selects rather than to a function the tests never reached. Open the file and line before reading one as a coverage gap.

@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch from f7111e1 to 73db1b9 Compare October 13, 2026 13:52
@grubmeshi grubmeshi changed the title feat(client): publish the HTTP layer as client/http, with Basic auth feat: basic auth credential and the runner API in client Oct 13, 2026
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch from 73db1b9 to ebf91ce Compare October 13, 2026 13:58
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch 2 times, most recently from 9ab69a7 to 322b873 Compare October 15, 2026 19:18
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch 10 times, most recently from 3a034bf to eb512e3 Compare October 23, 2026 11:53
@grubmeshi grubmeshi changed the title feat: basic auth credential and the runner API in client feat: basic auth, client/http and the runner API in client Oct 23, 2026
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch 2 times, most recently from 5975d78 to 98854c7 Compare October 28, 2026 11:58
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch 3 times, most recently from abbd309 to e90226d Compare October 29, 2026 04:56
@grubmeshi grubmeshi changed the title feat: basic auth, client/http and the runner API in client feat(client): add the runner API and export the HTTP client as client/http Oct 29, 2026
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch 2 times, most recently from c85b993 to 0332c2c Compare October 30, 2026 09:04
Comment thread client/http/options.go Outdated
if body == nil {
return
}
WithHeader("Content-Type", contentType)(opts)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f: introduce WithContentType (using WithHeader), so have the string Content-Type then only there defined once

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added http.WithContentType; WithBody, WithBodyFile, WithJsonPayload, WithFormPayload, AbortRun and ClaimRun use it, so Content-Type is spelled only there.

Comment thread client/runner_test.go Outdated
"github.com/meshcloud/meshstack-cli/internal/testutil/fakemeshstack"
)

func TestRunnerRun(t *testing.T) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f: do not have this test or this logic here in cli client, discuss how to move into bb runner repo

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved TestRunnerRun and its fixture to the runner (internal/executor/runyml_test.go). The decoding of inputs and implementation variants stays, as it reads the claim response, and so does MeshRunnerRunImplementation.MarshalJSON, so the public type encodes what it decodes. If you want it out of the CLI, the runner could encode runs with a json/v2 WithMarshalers option instead.

Comment thread client/api_surface_test.go Outdated

// TestPublicApiNamesNoInternalType keeps client callable from another module, which Go's internal
// rule forbids to name an internal type.
func TestPublicApiNamesNoInternalType(t *testing.T) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f: remove this test, rely on instructions / already complying design

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed; the development skill keeps the rule as one line.

Comment thread client/runner.go Outdated
Comment on lines +354 to +356
ForRun(run MeshRunnerRun) MeshRunnerRunClient
// ForRunUuid authorizes with the runner's own credentials and can only register a source and patch its status.
ForRunUuid(runUuid uuid.UUID) MeshRunnerRunClient

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f: remove this / move this to the bb runner repo, using the client/http AUthorization interface if possible (which allows to just provide the bearer token aka the run token then i hope)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ForRunUuid is gone; ForRun(auth http.Authorization, links MeshRunnerRunLinks) is the only way to a run client. The runner passes http.BearerToken(run token) in the child and its session in the poller, which builds the source links from the run uuid itself (building-block-runner#86).

@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch 2 times, most recently from 2ac56de to 3926fcc Compare November 2, 2026 11:36
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch from 3926fcc to 8e92887 Compare November 11, 2026 23:13
Comment thread docs/demo/fakemeshstack/server.go Fixed
grubmeshi and others added 7 commits November 12, 2026 03:52
…un without a stored one

A command takes the profile that --profile or MESHSTACK_PROFILE names, and an unknown name is an
error. Without a name it takes the current profile when no endpoint is given or the profile has
that endpoint, else the only stored profile with that endpoint. With no such profile it runs with
the endpoint and the credential from the settings alone: it stores nothing and caches no token.
Only 'meshstack login' creates a profile.

An endpoint is a scheme and a host, and one with a path is refused. 'meshstack api <URL>' takes
the origin of the URL as the endpoint.

A profile stores an API token with its other credentials. A token that an earlier version cached
is gone, so log in with --apitoken again.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…ion to client/types/version

Another module can then name the HTTP client, its request options and the version type that
client/ already uses in its exported API. The files move unchanged, apart from import paths.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…Client and hal.Links

Every kind's client is client.MeshObjectClient[M, Id, Filter] with Read, List, Create, Update and
Delete under a type alias, and List reads a page only when the caller asks for an object of it.
An action of an object follows a link of its _links through hal.Links: Get, Post and Delete send
the media type of the kind, decode the answer and let its links follow themselves too. A link to
another origin than the endpoint is refused. client.Raw and the per-kind methods such as
ReadFunc, TriggerRun and GetLogs are gone.

client/http has one DoRequest, which returns the response body, and UnmarshalJsonBody,
ReadAllBody and IgnoreResponse consume it. Request options set the retry policy, refuse
redirects and capture the response header. A GET and a DELETE are retried on every transient
failure, any other method on 423, 429 and 503. The debug log shows the first 1024 bytes of a
body as they came.

internal/json is the only importer of encoding/json/v2. The polymorph package reads and writes
a struct by its type property, as the implementation of a definition version needs. The API docs
are cached by the ETag of /api/openapi.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
MeshBuildingBlockRunnerImplementationTypes is an enum.Enum like the other enums of the client,
and MeshBuildingBlockRunnerSpec.ImplementationType is an entry of it.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…hrough the run client

A building block runner works with client.Client.BuildingBlockRun: Claim hands it the next run
with the run token, the inputs and the implementation, and sends the version of the HTTP
client's user agent as X-Meshcloud-Runner-Version. RegisterSource, UpdateSourceSteps,
DownloadArtifact and UploadArtifact address a run by its uuid, because the API key of a runner
may not read a run. The names follow the operations of the meshObject API.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
http.Error.IsTemporary is true for 408, 423, 429 and every 5xx, so that a caller that polls, as
a runner does for a pipeline run, knows when to go on.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Go 1.27.0 has GO-2026-6859 in net/http, which fails the vulnerability check.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@grubmeshi
grubmeshi force-pushed the feature/single-go-bin-runner branch from 2d49f9d to 9f1ecad Compare November 12, 2026 02:53
@sonarqubecloud

Copy link
Copy Markdown

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.

2 participants