Documentation
¶
Overview ¶
Package skills holds shared, dependency-light helpers for the Chainguard skills harden API that both the mono server and the chainctl client link — chiefly HardenJobID, the deterministic harden job id. See HardenJobID for how the id is computed and why the two callers must hash identically.
Index ¶
Examples ¶
Constants ¶
const GateRejectedMessage = "post-evaluation gate rejected hardened skill"
GateRejectedMessage is the Operation.error message a harden operation carries when the post-evaluation gate rejects the hardened skill. It is deliberately distinct from the generic hardening failure so a client can tell a verdict ("the gate looked at this and said no") from an outage ("we never got a verdict"), and retry only the latter. Both the service that produces it and the variance measurement that classifies it read this constant, so the two cannot drift apart silently.
const HardenNamePrefix = "harden/"
HardenNamePrefix is the prefix of every harden operation name. The operation name is the job id, namespaced under the target group: "harden/{group-uidp}/{jobhash}".
Variables ¶
This section is empty.
Functions ¶
func GroupFromHardenName ¶
GroupFromHardenName extracts the group UIDP embedded in a harden operation name. The name is "harden/{group}/{jobhash}"; the group UIDP may itself contain "/" (hierarchical UIDPs), so the job hash is the final path segment and the group is everything before it. It is the inverse of HardenOperationName and the boundary the api-impl cross-tenant read check uses to confirm a caller's group owns an operation.
Example ¶
package main
import (
"fmt"
"chainguard.dev/sdk/skills"
)
func main() {
name := skills.HardenOperationName("org1/child", "user1", "pdf", "sha256:abc")
group, err := skills.GroupFromHardenName(name)
fmt.Println(err)
fmt.Println(group)
}
Output: <nil> org1/child
func HardenJobID ¶
HardenJobID computes the deterministic harden job id from its four content dimensions. It is content-addressed, so identical inputs always yield the same id — the property the operation store relies on for idempotent submit (a re-submit of the same skill into the same group by the same user is a no-op).
- orgID: the target group UIDP (authorized against the caller).
- userID: the submitting user's identity subject, so each user gets their own tracked job.
- skillName: the skill's catalog name.
- contentDigest: the sha256 digest of the uploaded uploads.cgr.dev artifact.
Two users hardening the same bundle run separate jobs AND land separate outputs: each user's hardened artifact is published under a per-user path, skills.cgr.dev/<group>/<user>/<skill_name>@sha256:<hardened-digest>, so the two never overwrite or race the same digest. The user-less skills.cgr.dev/<group>/<skill_name> path is reserved for promotion (blessing a hardened skill to the org level). userID being a dimension of both this id and the output path is what keeps that per-user isolation intact.
The returned value is a hex sha256 over a version tag and the four fields, each length-prefixed so no field boundary is ambiguous (e.g. so a userID ending in the skillName's prefix cannot alias a different split).
IMPORTANT: this MUST hash identically to the chainctl client's local recomputation and to skillchain2's job key. Any change here is a coordinated cross-repo change; bump hardenJobIDVersion rather than silently altering the input encoding.
Example ¶
package main
import (
"fmt"
"chainguard.dev/sdk/skills"
)
func main() {
// The same inputs always yield the same id (idempotent submit / dedupe).
a := skills.HardenJobID("org1", "user1", "pdf", "sha256:abc")
b := skills.HardenJobID("org1", "user1", "pdf", "sha256:abc")
fmt.Println(a == b)
// A different content digest yields a different id.
c := skills.HardenJobID("org1", "user1", "pdf", "sha256:def")
fmt.Println(a == c)
}
Output: true false
func HardenOperationName ¶
HardenOperationName returns the full operation name for a harden job: the job id namespaced under the target group. Both the store record and the id handed to skillchain2 use this name.
Example ¶
package main
import (
"fmt"
"strings"
"chainguard.dev/sdk/skills"
)
func main() {
name := skills.HardenOperationName("org1/child", "user1", "pdf", "sha256:abc")
fmt.Println(strings.HasPrefix(name, "harden/org1/child/"))
}
Output: true
func HardenRetryOperationName ¶ added in v0.1.293
HardenRetryOperationName derives the next attempt from a failed operation's full name. Transport retries therefore return the same attempt; a further retry must name the newly failed operation. The caller verifies ownership and failure before creating it.
Example ¶
package main
import (
"fmt"
"chainguard.dev/sdk/skills"
)
func main() {
failed := skills.HardenOperationName("org/child", "user", "pdf", "sha256:abc")
retry, err := skills.HardenRetryOperationName(failed)
if err != nil {
fmt.Println(err)
return
}
repeated, err := skills.HardenRetryOperationName(failed)
if err != nil {
fmt.Println(err)
return
}
group, err := skills.GroupFromHardenName(retry)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(group, retry != failed, retry == repeated)
}
Output: org/child true true
Types ¶
This section is empty.