mirror of https://github.com/vernonkeenan/lib
389 lines
11 KiB
Go
389 lines
11 KiB
Go
package stash_client_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
openapiruntime "github.com/go-openapi/runtime"
|
|
"github.com/go-openapi/strfmt"
|
|
|
|
"code.tnxs.net/vernonkeenan/lib/api/stash/stash_client/stash_pdf"
|
|
"code.tnxs.net/vernonkeenan/lib/api/stash/stash_models"
|
|
)
|
|
|
|
type pdfMetadataCaptureTransport struct {
|
|
operation *openapiruntime.ClientOperation
|
|
}
|
|
|
|
func (transport *pdfMetadataCaptureTransport) Submit(
|
|
operation *openapiruntime.ClientOperation,
|
|
) (any, error) {
|
|
return transport.SubmitContext(context.Background(), operation)
|
|
}
|
|
|
|
func (transport *pdfMetadataCaptureTransport) SubmitContext(
|
|
_ context.Context,
|
|
operation *openapiruntime.ClientOperation,
|
|
) (any, error) {
|
|
transport.operation = operation
|
|
switch operation.ID {
|
|
case "listPdfs":
|
|
return stash_pdf.NewListPdfsOK(), nil
|
|
case "getPdfs":
|
|
return stash_pdf.NewGetPdfsOK(), nil
|
|
default:
|
|
panic("unexpected generated Stash PDF operation: " + operation.ID)
|
|
}
|
|
}
|
|
|
|
type pdfMetadataRequest struct {
|
|
headers http.Header
|
|
query url.Values
|
|
path map[string]string
|
|
timeout time.Duration
|
|
}
|
|
|
|
func newPDFMetadataRequest() *pdfMetadataRequest {
|
|
return &pdfMetadataRequest{
|
|
headers: make(http.Header),
|
|
query: make(url.Values),
|
|
path: make(map[string]string),
|
|
}
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) SetHeaderParam(name string, values ...string) error {
|
|
request.headers.Del(name)
|
|
for _, value := range values {
|
|
request.headers.Add(name, value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) GetHeaderParams() http.Header {
|
|
return request.headers
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) SetQueryParam(name string, values ...string) error {
|
|
request.query[name] = append([]string(nil), values...)
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) SetFormParam(string, ...string) error {
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) SetPathParam(name, value string) error {
|
|
request.path[name] = value
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) GetQueryParams() url.Values {
|
|
return request.query
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) SetFileParam(string, ...openapiruntime.NamedReadCloser) error {
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) SetBodyParam(any) error {
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) SetTimeout(timeout time.Duration) error {
|
|
request.timeout = timeout
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) GetMethod() string {
|
|
return ""
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) GetPath() string {
|
|
return ""
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) GetBody() []byte {
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) GetBodyParam() any {
|
|
return nil
|
|
}
|
|
|
|
func (request *pdfMetadataRequest) GetFileParam() map[string][]openapiruntime.NamedReadCloser {
|
|
return nil
|
|
}
|
|
|
|
func compoundPDFMetadataAuth(apiKey, session string) openapiruntime.ClientAuthInfoWriter {
|
|
return openapiruntime.ClientAuthInfoWriterFunc(
|
|
func(request openapiruntime.ClientRequest, _ strfmt.Registry) error {
|
|
if err := request.SetHeaderParam("X-API-Key", apiKey); err != nil {
|
|
return err
|
|
}
|
|
return request.SetHeaderParam("Cookie", "kvSession="+session)
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestGeneratedPDFMetadataOperationContract(t *testing.T) {
|
|
auth := compoundPDFMetadataAuth("fixture-api-key", "fixture-session")
|
|
tests := []struct {
|
|
name string
|
|
wantID string
|
|
wantMethod string
|
|
wantPath string
|
|
call func(openapiruntime.ContextualTransport) error
|
|
}{
|
|
{
|
|
name: "list",
|
|
wantID: "listPdfs",
|
|
wantMethod: http.MethodGet,
|
|
wantPath: "/pdfs",
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
|
_, err := stash_pdf.New(transport, strfmt.Default).ListPdfs(
|
|
stash_pdf.NewListPdfsParams(), auth,
|
|
)
|
|
return err
|
|
},
|
|
},
|
|
{
|
|
name: "get",
|
|
wantID: "getPdfs",
|
|
wantMethod: http.MethodGet,
|
|
wantPath: "/pdfs/{pdfId}",
|
|
call: func(transport openapiruntime.ContextualTransport) error {
|
|
_, err := stash_pdf.New(transport, strfmt.Default).GetPdfs(
|
|
stash_pdf.NewGetPdfsParams().WithPdfID("pdf-fixture"), auth,
|
|
)
|
|
return err
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
transport := &pdfMetadataCaptureTransport{}
|
|
if err := test.call(transport); err != nil {
|
|
t.Fatalf("generated client operation failed: %v", err)
|
|
}
|
|
if transport.operation == nil {
|
|
t.Fatal("generated client did not submit an operation")
|
|
}
|
|
if transport.operation.ID != test.wantID {
|
|
t.Errorf("operation ID = %q, want %q", transport.operation.ID, test.wantID)
|
|
}
|
|
if transport.operation.Method != test.wantMethod {
|
|
t.Errorf("method = %q, want %q", transport.operation.Method, test.wantMethod)
|
|
}
|
|
if transport.operation.PathPattern != test.wantPath {
|
|
t.Errorf("path = %q, want %q", transport.operation.PathPattern, test.wantPath)
|
|
}
|
|
if transport.operation.AuthInfo == nil {
|
|
t.Fatal("generated operation discarded compound auth writer")
|
|
}
|
|
|
|
request := newPDFMetadataRequest()
|
|
if err := transport.operation.AuthInfo.AuthenticateRequest(request, strfmt.Default); err != nil {
|
|
t.Fatalf("authenticate request: %v", err)
|
|
}
|
|
if got := request.headers.Get("X-API-Key"); got != "fixture-api-key" {
|
|
t.Errorf("X-API-Key = %q, want fixture value", got)
|
|
}
|
|
if got := request.headers.Get("Cookie"); got != "kvSession=fixture-session" {
|
|
t.Errorf("Cookie = %q, want only kvSession", got)
|
|
}
|
|
if len(request.headers) != 2 {
|
|
t.Errorf("compound auth wrote unexpected headers: %v", request.headers)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGeneratedPDFMetadataParameters(t *testing.T) {
|
|
limit, offset := int64(100), int64(10000)
|
|
listRequest := newPDFMetadataRequest()
|
|
if err := stash_pdf.NewListPdfsParams().
|
|
WithLimit(&limit).
|
|
WithOffset(&offset).
|
|
WriteToRequest(listRequest, strfmt.Default); err != nil {
|
|
t.Fatalf("write list params: %v", err)
|
|
}
|
|
if got := listRequest.query.Get("limit"); got != "100" {
|
|
t.Errorf("limit = %q, want 100", got)
|
|
}
|
|
if got := listRequest.query.Get("offset"); got != "10000" {
|
|
t.Errorf("offset = %q, want 10000", got)
|
|
}
|
|
|
|
getRequest := newPDFMetadataRequest()
|
|
if err := stash_pdf.NewGetPdfsParams().
|
|
WithPdfID("pdf-fixture").
|
|
WriteToRequest(getRequest, strfmt.Default); err != nil {
|
|
t.Fatalf("write get params: %v", err)
|
|
}
|
|
if got := getRequest.path["pdfId"]; got != "pdf-fixture" {
|
|
t.Errorf("pdfId = %q, want fixture value", got)
|
|
}
|
|
}
|
|
|
|
func TestPDFMetadataModelIsSanitized(t *testing.T) {
|
|
modelType := reflect.TypeOf(stash_models.Document{})
|
|
wantFields := map[string]string{
|
|
"Filename": "string",
|
|
"ID": "string",
|
|
"Title": "string",
|
|
"URI": "string",
|
|
}
|
|
if modelType.NumField() != len(wantFields) {
|
|
t.Fatalf("Document has %d fields, want %d", modelType.NumField(), len(wantFields))
|
|
}
|
|
for fieldName, wantType := range wantFields {
|
|
field, exists := modelType.FieldByName(fieldName)
|
|
if !exists {
|
|
t.Errorf("Document is missing %s", fieldName)
|
|
continue
|
|
}
|
|
if got := field.Type.String(); got != wantType {
|
|
t.Errorf("Document.%s type = %s, want %s", fieldName, got, wantType)
|
|
}
|
|
}
|
|
|
|
encoded, err := json.Marshal(stash_models.Document{
|
|
ID: "pdf-fixture",
|
|
Filename: "fixture.pdf",
|
|
Title: "Fixture",
|
|
URI: "/fixture.pdf",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal Document: %v", err)
|
|
}
|
|
for _, forbidden := range []string{
|
|
"HTML", "PDF", "ParentID", "SagaType", "OwnerID", "CreatedByID", "TenantID",
|
|
} {
|
|
if strings.Contains(string(encoded), forbidden) {
|
|
t.Errorf("sanitized metadata encoded forbidden field %q: %s", forbidden, encoded)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGeneratedPDFMetadataSurfaceIsReadOnly(t *testing.T) {
|
|
clientType := reflect.TypeOf((*stash_pdf.ClientService)(nil)).Elem()
|
|
for index := 0; index < clientType.NumMethod(); index++ {
|
|
method := clientType.Method(index).Name
|
|
for _, forbiddenPrefix := range []string{
|
|
"Post", "Put", "Patch", "Delete", "Create", "Render", "Update",
|
|
} {
|
|
if strings.HasPrefix(method, forbiddenPrefix) {
|
|
t.Errorf("Stash PDF metadata client exposes mutation method %s", method)
|
|
}
|
|
}
|
|
}
|
|
|
|
repoRoot := pdfMetadataRepoRoot(t)
|
|
removed := []string{
|
|
filepath.Join(repoRoot, "api", "stash", "stash_client", "stash_pdf", "post_pdfs_parameters.go"),
|
|
filepath.Join(repoRoot, "api", "stash", "stash_client", "stash_pdf", "post_pdfs_responses.go"),
|
|
filepath.Join(repoRoot, "api", "stash", "stash_models", "new_p_d_f.go"),
|
|
filepath.Join(repoRoot, "api", "stash", "stash_models", "p_d_f_request.go"),
|
|
filepath.Join(repoRoot, "api", "stash", "stash_models", "request_meta.go"),
|
|
}
|
|
for _, path := range removed {
|
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
|
t.Errorf("legacy mutation artifact still exists: %s", path)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPDFMetadataProjectionPinsCompoundAuthAndBounds(t *testing.T) {
|
|
specText := readPDFMetadataProjection(t)
|
|
required := []string{
|
|
"x-provider-pr: \"vernonkeenan/stash#16\"",
|
|
"x-provider-head: \"b2f5b4a6ae5ff507dfdc86bb7b9ee5a9bb924131\"",
|
|
"operationId: listPdfs",
|
|
"operationId: getPdfs",
|
|
"maximum: 100",
|
|
"maximum: 10000",
|
|
" - ApiKeyAuth: []\n kvSessionCookie: []",
|
|
}
|
|
for _, fragment := range required {
|
|
if !strings.Contains(specText, fragment) {
|
|
t.Errorf("client projection is missing %q", fragment)
|
|
}
|
|
}
|
|
for _, forbidden := range []string{
|
|
"\n post:", "\n put:", "\n patch:", "\n delete:",
|
|
"HTML:", "PDF:", "OwnerID:", "ParentID:", "SagaType:",
|
|
} {
|
|
if strings.Contains(specText, forbidden) {
|
|
t.Errorf("client projection exposes forbidden contract fragment %q", forbidden)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGeneratedPDFMetadataSurfaceHasNoExternalBypassOrSecrets(t *testing.T) {
|
|
repoRoot := pdfMetadataRepoRoot(t)
|
|
target := filepath.Join(repoRoot, "api", "stash")
|
|
credentialLiteral := regexp.MustCompile(
|
|
`(?i)(api[_-]?key|password|secret)\s*[:=]\s*["'][^"']+["']`,
|
|
)
|
|
err := filepath.WalkDir(target, func(path string, entry os.DirEntry, walkErr error) error {
|
|
if walkErr != nil {
|
|
return walkErr
|
|
}
|
|
if entry.IsDir() || !strings.HasSuffix(path, ".go") ||
|
|
strings.HasSuffix(path, "_test.go") {
|
|
return nil
|
|
}
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lower := strings.ToLower(string(content))
|
|
for _, forbidden := range []string{
|
|
"salesforce", "sf-gate", "go-force", "private key-----",
|
|
"postpdf", "putpdf", "deletepdf", "renderpdf",
|
|
} {
|
|
if strings.Contains(lower, forbidden) {
|
|
t.Errorf("%s contains forbidden boundary %q", path, forbidden)
|
|
}
|
|
}
|
|
if credentialLiteral.Match(content) {
|
|
t.Errorf("%s contains a credential-shaped literal", path)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("scan generated Stash target: %v", err)
|
|
}
|
|
}
|
|
|
|
func pdfMetadataRepoRoot(t *testing.T) string {
|
|
t.Helper()
|
|
_, sourceFile, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
t.Fatal("resolve test source path")
|
|
}
|
|
return filepath.Clean(filepath.Join(filepath.Dir(sourceFile), "..", "..", ".."))
|
|
}
|
|
|
|
func readPDFMetadataProjection(t *testing.T) string {
|
|
t.Helper()
|
|
content, err := os.ReadFile(filepath.Join(
|
|
pdfMetadataRepoRoot(t), "swagger", "client", "stash-pdf-metadata.yaml",
|
|
))
|
|
if err != nil {
|
|
t.Fatalf("read Stash PDF metadata projection: %v", err)
|
|
}
|
|
return string(content)
|
|
}
|