Skip to content

Conversation

@Marat-Tim
Copy link
Contributor

I have two files:

bipki.yaml

openapi: 3.0.3
info:
  title: Bipki
  version: 1.0.0
  contact:
    email: bipki@bipki
  description: ...
paths:
  '/bipkiLol':
    $ref: 'bipkiPath.yaml'

bipkiPath.yaml

get:
  tags:
    - Bipki
  summary: Get bipki
  operationId: getBipki
  responses:
    "200":
      description: OK
      content:
        application/json:
          schema:
            type: object
            properties:
              id:
                type: string

If I lint bipki.yaml then such error will be found

...
example/bipki.yaml:3:7        ▲           tag `Bipki` for `GET` operation is not defined as a global tag   
...

This is not correct, because error is located in file bipkiPath.yaml

To correct the error, I added field Origin to RuleFunctionResult as is done in other rules

I want to write test, but I am newbie in GO and this project. Are there any examples of tests in the project that work with multifile spec? I could try to write a new one based on them

@Marat-Tim
Copy link
Contributor Author

@daveshanley please take a look

Copy link
Owner

@daveshanley daveshanley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually fine, thank you, this is correct

@daveshanley
Copy link
Owner

You will need to set up the test properly to use the rolodex. you can find examples of how to do this in other openapi functions like the examples functions.

@Marat-Tim
Copy link
Contributor Author

@daveshanley I couldn't find any examples of such tests. Only one test mentions multifile somehow. But when you run it, it gives this error

{
  "level": "ERROR",
  "msg": "unable to open the rolodex file, check specification references and base path",
  "error": "rolodex has no file systems configured, cannot open '.../vacuum/functions/openapi/child.yaml'. Add a BaseURL or BasePath to your configuration so the rolodex knows how to resolve references"
}

So basically, it doesn't work with multi-file openapi

Now I think that I need to create a virtual file system, which seems complicated. Could you give me a more detailed path to example of a test with a multi-file openapi?

@daveshanley
Copy link
Owner

Hi.

https://github.com/pb33f/libopenapi/blob/main/document_test.go#L1522C1-L1534C2
https://github.com/pb33f/libopenapi/blob/main/index/rolodex_test.go#L703

func TestTagDefined_RunRule_MultiFile_CorrectOrigin(t *testing.T) {
      // Create temp directory
      tmpDir := t.TempDir()

      // Main spec that references an external path
      mainSpec := `openapi: 3.0.1
  tags:
    - name: "ValidTag"
  paths:
    /external:
      $ref: 'external-path.yaml'`

      // External file with an undefined tag
      externalPath := `get:
    tags:
      - "UndefinedTag"
    responses:
      "200":
        description: OK`

      // Write files
      err := os.WriteFile(filepath.Join(tmpDir, "main.yaml"), []byte(mainSpec), 0644)
      assert.NoError(t, err)
      err = os.WriteFile(filepath.Join(tmpDir, "external-path.yaml"), []byte(externalPath), 0644)
      assert.NoError(t, err)

      // Read the main spec
      specBytes, err := os.ReadFile(filepath.Join(tmpDir, "main.yaml"))
      assert.NoError(t, err)

      // Configure document with file references enabled
      config := datamodel.NewDocumentConfiguration()
      config.BasePath = tmpDir
      config.AllowFileReferences = true

      document, err := libopenapi.NewDocumentWithConfiguration(specBytes, config)
      assert.NoError(t, err)

      m, errs := document.BuildV3Model()
      assert.NoError(t, errs)

      drDocument := drModel.NewDrDocument(m)

      rule := buildOpenApiTestRuleAction("$", "tag-defined", "", nil)
      ctx := buildOpenApiTestContext(model.CastToRuleAction(rule.Then), nil)
      ctx.Document = document
      ctx.DrDocument = drDocument
      ctx.Rule = &rule                                                                                                          
      ctx.Index = m.Index // Important: use the resolved index

      def := TagDefined{}
      res := def.RunRule(nil, ctx)

      // Should find one violation
      assert.Len(t, res, 1)
      assert.Equal(t, "tag `UndefinedTag` for `GET` operation is not defined as a global tag", res[0].Message)

      // Key assertion: Origin should point to the external file, not main.yaml
      assert.NotNil(t, res[0].Origin)
      assert.True(t, strings.HasSuffix(res[0].Origin.AbsoluteLocation, "external-path.yaml"),
          "Expected origin to be external-path.yaml but got: %s", res[0].Origin.AbsoluteLocation)
  }

The problem you have is trying to use raw yaml parsing + rolodex directly. The issue is that when using libopenapi.NewDocument() without configuration, it doesn't enable file lookups. The key is using NewDocumentWithConfiguration() with:

config := datamodel.NewDocumentConfiguration()
config.BasePath = "path/to/spec/directory"
config.AllowFileReferences = true

This tells libopenapi to create the rolodex with a local filesystem configured, which is what enables rolodex.FindNodeOrigin(node) to work correctly.

@Marat-Tim
Copy link
Contributor Author

@daveshanley thanks for your help, the test worked. Now everything seems to be ready. Do I need to fix the pipeline somehow?

@Marat-Tim
Copy link
Contributor Author

@daveshanley

@Marat-Tim Marat-Tim requested a review from daveshanley January 19, 2026 09:00
Copy link
Owner

@daveshanley daveshanley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me, thank you!

@daveshanley daveshanley added the release/patch Patch / non-breaking release label Jan 19, 2026
@daveshanley daveshanley merged commit 3df8a76 into daveshanley:main Jan 19, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release/patch Patch / non-breaking release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants