From 0e6eba52d04adb556469f432d6292bf27db5e2a5 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Aug 2026 18:23:32 +1000 Subject: [PATCH 1/3] fix(request): never emit a dangling ? for an empty query string url.Parse records a trailing ? as ForceQuery and reproduces it on the wire. Signature schemes covering (request-target) then fail against servers that normalise the request line before verification - live OCI rejects every no-query body verb with 401 NotAuthenticated (GETs escape because they always carry real query params). Found by the oci provider live smoke; the signed-mock integration suite could not catch it because the dangling ? is self-consistent between signing and wire. Co-Authored-By: Claude Fable 5 --- internal/anysdk/operation_store.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/internal/anysdk/operation_store.go b/internal/anysdk/operation_store.go index f1c672d..b455832 100644 --- a/internal/anysdk/operation_store.go +++ b/internal/anysdk/operation_store.go @@ -1735,14 +1735,21 @@ func (op *standardOpenAPIOperationStore) parameterize(prov Provider, parentDoc S // TODO: clean up sv = strings.TrimSuffix(sv, "/") path := replaceSimpleStringVars(fmt.Sprintf("%s%s", sv, op.OperationRef.extractPathItem()), pathParams) - u, err := url.Parse(fmt.Sprintf("%s?%s", path, q.Encode())) - if strings.Contains(path, "?") { - if len(q) > 0 { - u, err = url.Parse(fmt.Sprintf("%s&%s", path, q.Encode())) - } else { - u, err = url.Parse(path) - } - } + // Never emit a dangling "?" for an empty query: url.Parse records it as + // ForceQuery and reproduces it on the wire, and signature schemes that + // cover (request-target) then fail against servers that normalise the + // request line before verification (OCI 401 NotAuthenticated on every + // no-query body verb). + encodedQuery := q.Encode() + rawURL := path + if encodedQuery != "" { + separator := "?" + if strings.Contains(path, "?") { + separator = "&" + } + rawURL = fmt.Sprintf("%s%s%s", path, separator, encodedQuery) + } + u, err := url.Parse(rawURL) if err != nil { return nil, err } From 8f975b9dda8a996a1304d588db3c637b87ce26ae Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Aug 2026 18:43:28 +1000 Subject: [PATCH 2/3] feat(auth): doc-level OCI env var indirections for oci_signing_v1 A provider doc may now ship default env var names in its config.auth block (tenancy_ocid_envvar, user_ocid_envvar, fingerprint_envvar, private_key_envvar, private_key_path_envvar, passphrase_envvar, region_envvar) so a populated environment needs no runtime --auth context, matching the credentialsenvvar convention of the API-key auth types. Indirections only - literal credential values remain runtime auth context territory. Plumbed through the internal DTO, authsurface and formulation wrapper layers; consumers map these onto the runtime AuthCtx Oci* fields (stackql wire-through tracked separately). Co-Authored-By: Claude Fable 5 --- internal/anysdk/auth_dto.go | 47 ++++++++++++++++++++++++++++++++ pkg/authsurface/surface.go | 7 +++++ public/formulation/interfaces.go | 7 +++++ public/formulation/wrappers.go | 28 +++++++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/internal/anysdk/auth_dto.go b/internal/anysdk/auth_dto.go index 1266114..93a06c2 100644 --- a/internal/anysdk/auth_dto.go +++ b/internal/anysdk/auth_dto.go @@ -43,6 +43,13 @@ type AuthDTO interface { GetAuthStyle() int GetAccountID() string GetAccountIDEnvVar() string + GetOciTenancyOCIDEnvVar() string + GetOciUserOCIDEnvVar() string + GetOciFingerprintEnvVar() string + GetOciPrivateKeyEnvVar() string + GetOciPrivateKeyPathEnvVar() string + GetOciPassphraseEnvVar() string + GetOciRegionEnvVar() string } type standardAuthDTO struct { @@ -76,6 +83,46 @@ type standardAuthDTO struct { AuthStyle int `json:"auth_style" yaml:"auth_style"` AccoountID string `json:"account_id" yaml:"account_id"` AccountIDEnvVar string `json:"account_id_env_var" yaml:"account_id_var"` + // OCI signing (oci_signing_v1) doc-level env var indirections: a provider + // doc may ship default env var names so that a populated environment + // needs no runtime auth context at all. Only indirections are accepted + // at doc level - literal credential values belong exclusively in the + // runtime auth context. + OciTenancyOCIDEnvVar string `json:"tenancy_ocid_envvar,omitempty" yaml:"tenancy_ocid_envvar,omitempty"` + OciUserOCIDEnvVar string `json:"user_ocid_envvar,omitempty" yaml:"user_ocid_envvar,omitempty"` + OciFingerprintEnvVar string `json:"fingerprint_envvar,omitempty" yaml:"fingerprint_envvar,omitempty"` + OciPrivateKeyEnvVar string `json:"private_key_envvar,omitempty" yaml:"private_key_envvar,omitempty"` + OciPrivateKeyPathEnvVar string `json:"private_key_path_envvar,omitempty" yaml:"private_key_path_envvar,omitempty"` + OciPassphraseEnvVar string `json:"passphrase_envvar,omitempty" yaml:"passphrase_envvar,omitempty"` + OciRegionEnvVar string `json:"region_envvar,omitempty" yaml:"region_envvar,omitempty"` +} + +func (qt standardAuthDTO) GetOciTenancyOCIDEnvVar() string { + return qt.OciTenancyOCIDEnvVar +} + +func (qt standardAuthDTO) GetOciUserOCIDEnvVar() string { + return qt.OciUserOCIDEnvVar +} + +func (qt standardAuthDTO) GetOciFingerprintEnvVar() string { + return qt.OciFingerprintEnvVar +} + +func (qt standardAuthDTO) GetOciPrivateKeyEnvVar() string { + return qt.OciPrivateKeyEnvVar +} + +func (qt standardAuthDTO) GetOciPrivateKeyPathEnvVar() string { + return qt.OciPrivateKeyPathEnvVar +} + +func (qt standardAuthDTO) GetOciPassphraseEnvVar() string { + return qt.OciPassphraseEnvVar +} + +func (qt standardAuthDTO) GetOciRegionEnvVar() string { + return qt.OciRegionEnvVar } func (qt standardAuthDTO) GetAccountID() string { diff --git a/pkg/authsurface/surface.go b/pkg/authsurface/surface.go index 1d844d9..f102461 100644 --- a/pkg/authsurface/surface.go +++ b/pkg/authsurface/surface.go @@ -33,4 +33,11 @@ type AuthDTO interface { GetAuthStyle() int GetAccountID() string GetAccountIDEnvVar() string + GetOciTenancyOCIDEnvVar() string + GetOciUserOCIDEnvVar() string + GetOciFingerprintEnvVar() string + GetOciPrivateKeyEnvVar() string + GetOciPrivateKeyPathEnvVar() string + GetOciPassphraseEnvVar() string + GetOciRegionEnvVar() string } diff --git a/public/formulation/interfaces.go b/public/formulation/interfaces.go index c067dc9..e00bf12 100644 --- a/public/formulation/interfaces.go +++ b/public/formulation/interfaces.go @@ -768,6 +768,13 @@ type AuthDTO interface { GetKeyIDEnvVar() string GetLocation() string GetName() string + GetOciFingerprintEnvVar() string + GetOciPassphraseEnvVar() string + GetOciPrivateKeyEnvVar() string + GetOciPrivateKeyPathEnvVar() string + GetOciRegionEnvVar() string + GetOciTenancyOCIDEnvVar() string + GetOciUserOCIDEnvVar() string GetScopes() []string GetSubject() string GetSuccessor() (AuthDTO, bool) diff --git a/public/formulation/wrappers.go b/public/formulation/wrappers.go index 9affd8f..ebd5e4f 100644 --- a/public/formulation/wrappers.go +++ b/public/formulation/wrappers.go @@ -2631,6 +2631,34 @@ type wrappedAuthDTO struct { inner authsurface.AuthDTO } +func (w *wrappedAuthDTO) GetOciTenancyOCIDEnvVar() string { + return w.inner.GetOciTenancyOCIDEnvVar() +} + +func (w *wrappedAuthDTO) GetOciUserOCIDEnvVar() string { + return w.inner.GetOciUserOCIDEnvVar() +} + +func (w *wrappedAuthDTO) GetOciFingerprintEnvVar() string { + return w.inner.GetOciFingerprintEnvVar() +} + +func (w *wrappedAuthDTO) GetOciPrivateKeyEnvVar() string { + return w.inner.GetOciPrivateKeyEnvVar() +} + +func (w *wrappedAuthDTO) GetOciPrivateKeyPathEnvVar() string { + return w.inner.GetOciPrivateKeyPathEnvVar() +} + +func (w *wrappedAuthDTO) GetOciPassphraseEnvVar() string { + return w.inner.GetOciPassphraseEnvVar() +} + +func (w *wrappedAuthDTO) GetOciRegionEnvVar() string { + return w.inner.GetOciRegionEnvVar() +} + func (w *wrappedAuthDTO) GetAccountID() string { r0 := w.inner.GetAccountID() return r0 From f5d5ba65eb81ebbb9ed0965c3ba1e2a9ad6fc006 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Fri, 7 Aug 2026 08:57:18 +1000 Subject: [PATCH 3/3] refactor(auth): oci_ prefix on generic doc-level OCI auth keys fingerprint, private key and passphrase are generic terms other auth types may legitimately claim; the doc-level OCI keys now all carry an OCI reference at the operator surface (tenancy_ocid_envvar, user_ocid_envvar via 'ocid'; oci_fingerprint_envvar, oci_private_key_envvar, oci_private_key_path_envvar, oci_passphrase_envvar, oci_region_envvar). Go field and getter names unchanged - consumers are unaffected. Co-Authored-By: Claude Fable 5 --- internal/anysdk/auth_dto.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/anysdk/auth_dto.go b/internal/anysdk/auth_dto.go index 93a06c2..3f69f75 100644 --- a/internal/anysdk/auth_dto.go +++ b/internal/anysdk/auth_dto.go @@ -88,13 +88,17 @@ type standardAuthDTO struct { // needs no runtime auth context at all. Only indirections are accepted // at doc level - literal credential values belong exclusively in the // runtime auth context. + // Key naming: every property carries an OCI reference at the operator + // surface (tenancy_ocid/user_ocid via "ocid", the rest via an oci_ + // prefix) so generic terms (fingerprint, private key, passphrase) stay + // available to other auth types without collision. OciTenancyOCIDEnvVar string `json:"tenancy_ocid_envvar,omitempty" yaml:"tenancy_ocid_envvar,omitempty"` OciUserOCIDEnvVar string `json:"user_ocid_envvar,omitempty" yaml:"user_ocid_envvar,omitempty"` - OciFingerprintEnvVar string `json:"fingerprint_envvar,omitempty" yaml:"fingerprint_envvar,omitempty"` - OciPrivateKeyEnvVar string `json:"private_key_envvar,omitempty" yaml:"private_key_envvar,omitempty"` - OciPrivateKeyPathEnvVar string `json:"private_key_path_envvar,omitempty" yaml:"private_key_path_envvar,omitempty"` - OciPassphraseEnvVar string `json:"passphrase_envvar,omitempty" yaml:"passphrase_envvar,omitempty"` - OciRegionEnvVar string `json:"region_envvar,omitempty" yaml:"region_envvar,omitempty"` + OciFingerprintEnvVar string `json:"oci_fingerprint_envvar,omitempty" yaml:"oci_fingerprint_envvar,omitempty"` + OciPrivateKeyEnvVar string `json:"oci_private_key_envvar,omitempty" yaml:"oci_private_key_envvar,omitempty"` + OciPrivateKeyPathEnvVar string `json:"oci_private_key_path_envvar,omitempty" yaml:"oci_private_key_path_envvar,omitempty"` + OciPassphraseEnvVar string `json:"oci_passphrase_envvar,omitempty" yaml:"oci_passphrase_envvar,omitempty"` + OciRegionEnvVar string `json:"oci_region_envvar,omitempty" yaml:"oci_region_envvar,omitempty"` } func (qt standardAuthDTO) GetOciTenancyOCIDEnvVar() string {