Help us shape the future of Go! Take the 2026 Go Developer Survey

harness

package
v0.1.430 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package harness holds shared, dependency-light helpers for the Chainguard harness hunt API that both the mono server and the chainctl client link: HuntName, the deterministic hunt name, and ParseReportPublicKey, the check every report key must pass. See HuntName for what the name is derived from and why the two callers must hash identically.

Index

Examples

Constants

View Source
const HuntNamePrefix = "hunt/"

HuntNamePrefix is the prefix of every hunt name. A hunt name is the content-addressed hash namespaced under the submitting group: "hunt/{group-uidp}/{hunthash}".

View Source
const ReportKeyBits = 3072

ReportKeyBits is the RSA modulus size required for report recipient keys.

Variables

This section is empty.

Functions

func GroupFromHuntName

func GroupFromHuntName(name string) (string, error)

GroupFromHuntName extracts the group UIDP embedded in a hunt name. The name is "hunt/{group}/{hunthash}"; the group UIDP may itself contain "/" (hierarchical UIDPs), so the hash is the final path segment and the group is everything before it. It is the inverse of HuntName and the boundary the api-impl cross-tenant read check uses to confirm a caller's group owns a hunt.

Example
package main

import (
	"fmt"

	"chainguard.dev/sdk/harness"
)

func main() {
	group, err := harness.GroupFromHuntName(harness.HuntName("org1/child", "user1", "sha256:abc"))
	fmt.Println(err)
	fmt.Println(group)
}
Output:
<nil>
org1/child

func HuntName

func HuntName(orgID, actorID, bundleSHA256 string) string

HuntName computes the deterministic name of a hunt from its three content dimensions, namespaced under the submitting group. It is content-addressed, so identical inputs always yield the same name — the property CreateHunt's idempotency rests on. The hunt table carries a unique index on this name and CreateHunt is insert-if-absent, so resubmitting an identical bundle returns the existing hunt instead of starting a second hours-long run.

  • orgID: the submitting group's UIDP (authorized against the caller). It namespaces the hunt and is what GroupFromHuntName recovers for the cross-tenant read check.
  • actorID: the submitting identity's subject. Without it one member's create would silently return another member's hunt, handing them a status and rejection reason they did not produce; with it each submitter gets a hunt of their own to track.
  • bundleSHA256: the sha256 of the plaintext source bundle, as "sha256:<64-hex>". This is the content dimension: a changed tree is a different hunt, an unchanged tree is the same one.

The ciphertext envelope is deliberately not a dimension. It is sealed under a fresh per-upload key, so the same tree seals to different bytes every time and a resubmit would never match.

The returned name's hash segment is a hex sha256 over a version tag and the three fields, each length-prefixed so no field boundary is ambiguous (so an actorID ending in the digest's prefix cannot alias a different split).

IMPORTANT: this MUST hash identically to the chainctl client's local recomputation. Any change here is a coordinated cross-component change; bump huntNameVersion rather than silently altering the input encoding.

Example
package main

import (
	"fmt"
	"strings"

	"chainguard.dev/sdk/harness"
)

func main() {
	// The same inputs always yield the same name (idempotent CreateHunt).
	a := harness.HuntName("org1", "user1", "sha256:abc")
	b := harness.HuntName("org1", "user1", "sha256:abc")
	fmt.Println(a == b)
	// A different bundle digest is a different hunt.
	c := harness.HuntName("org1", "user1", "sha256:def")
	fmt.Println(a == c)
	// So is the same bundle submitted by a different member.
	d := harness.HuntName("org1", "user2", "sha256:abc")
	fmt.Println(a == d)
	fmt.Println(strings.HasPrefix(harness.HuntName("org1/child", "user1", "sha256:abc"), "hunt/org1/child/"))
}
Output:
true
false
false
true

func HuntRetryName

func HuntRetryName(failedHunt string) (string, error)

HuntRetryName derives the next attempt from a failed hunt's name. Transport retries therefore return the same attempt; a further retry must name the newly failed hunt, so one failed hunt has exactly one successor. The caller verifies ownership and failure before creating it.

Example
package main

import (
	"fmt"

	"chainguard.dev/sdk/harness"
)

func main() {
	failed := harness.HuntName("org/child", "user", "sha256:abc")
	retry, err := harness.HuntRetryName(failed)
	if err != nil {
		fmt.Println(err)
		return
	}
	repeated, err := harness.HuntRetryName(failed)
	if err != nil {
		fmt.Println(err)
		return
	}
	group, err := harness.GroupFromHuntName(retry)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(group, retry != failed, retry == repeated)
}
Output:
org/child true true

func ParseReportPublicKey

func ParseReportPublicKey(der []byte) (*rsa.PublicKey, error)

ParseReportPublicKey decodes and checks the DER SubjectPublicKeyInfo a client sends as CreateHunt's report_public_key. The key must have a ReportKeyBits modulus and support RSA-OAEP-SHA256 encryption. Validation errors identify the failed check so intake can reject the key before recording an immutable key that cannot seal a report.

Types

This section is empty.

Directories

Path Synopsis
Package bundle implements harness-source-v1alpha1, the single artifact a "chainctl harness hunt" submission becomes whatever source kind it was built from: a zstd-compressed tar of normalized entries with a manifest first.
Package bundle implements harness-source-v1alpha1, the single artifact a "chainctl harness hunt" submission becomes whatever source kind it was built from: a zstd-compressed tar of normalized entries with a manifest first.
Package reportenvelope is harness-report-envelope-v1alpha1, the sealed object a hunt report is stored and delivered as.
Package reportenvelope is harness-report-envelope-v1alpha1, the sealed object a hunt report is stored and delivered as.
Package upload seals a harness bundle to an organization's harness key and uploads it through the harness Uploads API: GetOrgPublicKey, CreateUpload, one PUT of the sealed bundle to the signed URL CreateUpload returns, then CompleteUpload.
Package upload seals a harness bundle to an organization's harness key and uploads it through the harness Uploads API: GetOrgPublicKey, CreateUpload, one PUT of the sealed bundle to the signed URL CreateUpload returns, then CompleteUpload.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL