Documentation
¶
Overview ¶
Package contract lets a plugin author verify a built plugin satisfies the OSCTF contract WITHOUT the monorepo — it dials the plugin exactly as the host does, wrapped so no wire type is exposed. Call it from a Go test (the template's plugin_test.go does): Build your plugin, then Verify* it. Designed alongside the SDK, not bolted on after, so it checks what matters (the handshake, the advertised type/ABI, and per-case behaviour) rather than what is convenient.
Index ¶
- func Build(tb testing.TB, dir string) string
- func VerifyChallengeType(tb testing.TB, binaryPath string, cases ChallengeTypeCases)
- func VerifyNotification(tb testing.TB, binaryPath string, cases []NotificationCase)
- func VerifyScoring(tb testing.TB, binaryPath string, cases []ScoringCase)
- type ChallengeTypeCases
- type NotificationCase
- type ScoringCase
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Build ¶
Build compiles the plugin whose main package is in dir to a temporary binary and returns its path, for passing to a Verify* function. It fails the test on a build error.
func VerifyChallengeType ¶
func VerifyChallengeType(tb testing.TB, binaryPath string, cases ChallengeTypeCases)
VerifyChallengeType launches the challenge-type plugin at binaryPath and asserts the contract that matters for a type that decides correctness:
- the handshake succeeds and Info advertises the challenge-type with a non-empty name/ABI;
- ValidateConfig ACCEPTS ValidConfig and REJECTS each RejectedConfig with a per-field error;
- CheckFlag is DETERMINISTIC (same input → same answer; a checker with hidden state is a bug);
- CheckFlag accepts Correct, rejects Incorrect, and ERRORS on Undecidable (fail-closed, so no attempt is burned) — all run against the NORMALIZED config the plugin itself returned.
func VerifyNotification ¶
func VerifyNotification(tb testing.TB, binaryPath string, cases []NotificationCase)
VerifyNotification launches the notification plugin at binaryPath and asserts the contract: the handshake succeeds, Info advertises the notification type with a non-empty name and ABI, Subscriptions is callable, and each case's event is delivered without a transport error. (It does not assert side effects — a notifier's real output is external; the contract is that the plugin accepts a subscribed event and does not fail the delivery RPC.)
func VerifyScoring ¶
func VerifyScoring(tb testing.TB, binaryPath string, cases []ScoringCase)
VerifyScoring launches the scoring plugin at binaryPath and asserts the contract: the handshake succeeds, Info advertises the scoring type with a non-empty name and ABI, each case's Value matches, and the scorer is deterministic (a pure scorer returns the same value for the same input). Reports failures through tb, so call it from a Go test.
Types ¶
type ChallengeTypeCases ¶
type ChallengeTypeCases struct {
// ValidConfig is a config the type accepts. Its NORMALIZED form — what the host stores and later
// hands back to CheckFlag — is what the flag cases below run against, so the checks exercise
// production's stored value, not the raw input.
ValidConfig map[string]string
// RejectedConfigs are configs the type MUST reject at author time, each with at least one
// per-field error. At least one is required: a ValidateConfig that returns OK unconditionally (a
// common author mistake) must fail this verifier.
RejectedConfigs []map[string]string
// Correct are submissions CheckFlag must accept — (true, no error). At least one required.
Correct []string
// Incorrect are submissions CheckFlag must reject — (false, no error). At least one required.
Incorrect []string
// Undecidable are submissions CheckFlag must fail on with an ERROR, not a false. The host fails
// CLOSED on an error and consumes NO attempt; returning false instead silently burns a player's
// attempt — the single most consequential thing a checker author can get wrong. Optional: a
// checker that can always decide (a regex either matches or not) has none, but if yours can hit
// an internal failure (a missing key, an external call), prove it errors rather than guessing.
Undecidable []string
}
ChallengeTypeCases specifies the author-supplied inputs VerifyChallengeType checks. A challenge-type plugin DECIDES CORRECTNESS, so the contract is behavioural — not just "the RPCs answer": provide config the type accepts and rejects, and flags it must accept, reject, and (if it can hit an internal failure) refuse to decide.
type NotificationCase ¶
NotificationCase is one event delivered to the plugin under test by VerifyNotification.