Clarify credential inspection and protect request privacy
This commit is contained in:
@@ -719,18 +719,19 @@ if err != nil {
|
||||
}
|
||||
|
||||
target := inspection.EffectiveModelParams
|
||||
if inspection.APIKeyRequired {
|
||||
// Arrange a usable direct or configured environment credential.
|
||||
}
|
||||
if target.APIKeyEnv != "" {
|
||||
// This is a configured optional environment lookup source.
|
||||
} else if inspection.APIKeyRequired {
|
||||
// Arrange a direct credential before later execution.
|
||||
// This is the configured environment lookup source, not its value.
|
||||
}
|
||||
```
|
||||
|
||||
Use this configuration-time boundary when only the profile and its target need
|
||||
checking. Use `Prepare` when the application also needs prompt, input, schema,
|
||||
or rendering work; use prepared execution when that work must remain tied to a
|
||||
later execution. A reported `APIKeyEnv` is a configured optional source, while
|
||||
`APIKeyRequired` is the explicit local requirement. The
|
||||
later execution. A reported `APIKeyEnv` identifies a configured source, while
|
||||
`APIKeyRequired` is the explicit requirement; both may be present. The
|
||||
[credential format reference](../formats.md#credentials) and the method's
|
||||
[GoDoc](../../engine.go) own the exact precedence, timing, result, and error
|
||||
contracts.
|
||||
|
||||
@@ -115,9 +115,10 @@ The client conditionally includes:
|
||||
strict flag, and schema document. Plain JSON validation does not add an
|
||||
object-only response constraint.
|
||||
|
||||
The engine resolves backend, profile, and request extra-parameter maps by
|
||||
whole-map replacement rather than key merging. The resulting effective map is
|
||||
merged into the top-level body. Empty keys, values that cannot be encoded, and
|
||||
Configured profile maps recursively overlay backend defaults, while a nonempty
|
||||
runtime override replaces the complete configured map. The [format reference](../formats.md#defaults-and-overrides)
|
||||
owns these resolution rules. The resulting effective map is merged into the
|
||||
top-level body. Empty keys, values that cannot be encoded, and
|
||||
collisions with these reserved fields are rejected before any provider call:
|
||||
|
||||
- `model`
|
||||
|
||||
@@ -715,6 +715,11 @@ Go 1.27.3; an injected-observer test verifies permit release before callbacks.
|
||||
boundary, and changed documentation links and semantics agree with canonical
|
||||
GoDoc/formats. Do not snapshot whole diagnostic strings or unrelated JSON fields.
|
||||
|
||||
Completion: marker-based request formatting and JSON checks cover value and
|
||||
pointer forms. Profile credential inspection, exact IDs, prompt listing, and
|
||||
provider-map precedence prose now match the implemented contracts. Focused
|
||||
privacy, profile, inheritance, and provider tests pass on Go 1.27.3.
|
||||
|
||||
## Stage 28: Give Bundled Catalog Expectations One Test Owner
|
||||
|
||||
**Catalog:** 28. **Scope:** catalog tests, not bundled asset changes.
|
||||
|
||||
@@ -312,8 +312,8 @@ func (e *Engine) InspectPrompt(
|
||||
// override. BackendID is empty for an endpoint-only profile.
|
||||
//
|
||||
// APIKeyEnv in the returned target is an environment-variable name, never its
|
||||
// value. APIKeyRequired instead reports a direct credential requirement and is
|
||||
// mutually exclusive with a nonblank APIKeyEnv. InspectProfile neither derives
|
||||
// value. APIKeyRequired reports that a credential is required; an explicit
|
||||
// profile environment source can also be present. InspectProfile neither derives
|
||||
// an ID from a prompt default_profile nor checks credential availability, so an
|
||||
// absent or blank named environment variable is not an error.
|
||||
//
|
||||
|
||||
@@ -93,8 +93,8 @@ func (e *Engine) ListProfiles(ctx context.Context, filters ...NamespaceFilter) (
|
||||
// behavior as [Engine.ListProfiles], using the prompt namespace by default.
|
||||
// At most one filter is accepted.
|
||||
//
|
||||
// The returned slice and each Version pointer are caller-owned and safe to
|
||||
// mutate while the engine is used concurrently. Empty inventories succeed.
|
||||
// The returned slice is caller-owned and safe to mutate while the engine is
|
||||
// used concurrently. Empty inventories succeed.
|
||||
//
|
||||
// Listing reports membership, not execution readiness. It does not reload
|
||||
// configuration or perform resource, credential, provider, or execution work.
|
||||
|
||||
46
request_privacy_contract_test.go
Normal file
46
request_privacy_contract_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package promptkit_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.maximumdirect.net/promptkit"
|
||||
)
|
||||
|
||||
func TestRunRequestFormattingAndJSONProtectDirectCredential(t *testing.T) {
|
||||
markers := []string{"secret-key-marker", "variable-marker", "artifact-body-marker", "message-body-marker", "setting-marker", "schema-path-marker"}
|
||||
request := promptkit.RunRequest{
|
||||
PromptID: "prompt", ProfileID: "profile", APIKey: markers[0],
|
||||
Vars: map[string]string{"name": markers[1]},
|
||||
Inputs: map[string]promptkit.ArtifactRef{"input": {Type: promptkit.ArtifactRefInline, Body: markers[2]}},
|
||||
AppendedMessages: []promptkit.RenderedMessage{{Role: promptkit.RoleUser, Content: markers[3]}},
|
||||
Execution: &promptkit.ExecutionTargetOverride{Model: markers[4]},
|
||||
Validation: &promptkit.OutputContract{SchemaPath: markers[5]},
|
||||
}
|
||||
for _, rendered := range []string{
|
||||
fmt.Sprintf("%v", request), fmt.Sprintf("%+v", request), fmt.Sprintf("%#v", request),
|
||||
fmt.Sprintf("%v", &request), fmt.Sprintf("%+v", &request), fmt.Sprintf("%#v", &request),
|
||||
request.String(), request.GoString(), (&request).String(), (&request).GoString(),
|
||||
} {
|
||||
for _, marker := range markers {
|
||||
if strings.Contains(rendered, marker) {
|
||||
t.Fatalf("request formatting exposes %q: %s", marker, rendered)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range []any{request, &request} {
|
||||
encoded, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var object map[string]any
|
||||
if err := json.Unmarshal(encoded, &object); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, found := object["APIKey"]; found || strings.Contains(string(encoded), markers[0]) {
|
||||
t.Fatal("request JSON exposed the direct credential")
|
||||
}
|
||||
}
|
||||
}
|
||||
8
types.go
8
types.go
@@ -363,7 +363,7 @@ type ExecutionTarget struct {
|
||||
// separate from that target to preserve ExecutionTarget's general execution
|
||||
// and stable JSON contracts.
|
||||
type ProfileInspection struct {
|
||||
// ProfileID is the trimmed, exact profile ID inspected by the engine.
|
||||
// ProfileID is the exact profile ID inspected by the engine.
|
||||
ProfileID string
|
||||
// EffectiveModelParams contains settings resolved from the framework timeout
|
||||
// baseline, selected backend, and then profile, without a request override.
|
||||
@@ -371,9 +371,9 @@ type ProfileInspection struct {
|
||||
// provider default. APIKeyEnv is an environment-variable name, never its
|
||||
// credential value.
|
||||
EffectiveModelParams ExecutionTarget
|
||||
// APIKeyRequired reports that a later execution must supply a direct API
|
||||
// key or an explicit request environment override. It is mutually exclusive
|
||||
// with a nonblank EffectiveModelParams.APIKeyEnv.
|
||||
// APIKeyRequired reports that a later execution must supply a usable direct
|
||||
// key or environment credential. An explicit profile environment source can
|
||||
// coexist with this requirement.
|
||||
APIKeyRequired bool
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user