Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VAULT-20669: Add New Authenticated Endpoint for Version #23740

Merged
Merged
3 changes: 3 additions & 0 deletions changelog/23740.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
core: add sys/internal/ui/version endpoint
```
12 changes: 12 additions & 0 deletions vault/logical_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -4754,6 +4754,18 @@ func (b *SystemBackend) pathInternalUIResultantACL(ctx context.Context, req *log
return resp, nil
}

// pathInternalUIVersion is the framework.PathOperation callback function for
// the sys/internal/ui/version path. It simply returns the Vault version.
func (b *SystemBackend) pathInternalUIVersion(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
marcboudreau marked this conversation as resolved.
Show resolved Hide resolved
resp := &logical.Response{
Data: map[string]any{
"version": version.GetVersion().VersionNumber(),
},
}

return resp, nil
}

func (b *SystemBackend) pathInternalOpenAPI(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
// Limit output to authorized paths
resp, err := b.pathInternalUIMountsRead(ctx, req, d)
Expand Down
5 changes: 5 additions & 0 deletions vault/logical_system_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ func TestSystemBackend_InternalUIResultantACL(t *testing.T) {
"read",
},
},
"sys/internal/ui/version": map[string]interface{}{
"capabilities": []interface{}{
"read",
},
},
"sys/leases/lookup": map[string]interface{}{
"capabilities": []interface{}{
"update",
Expand Down
25 changes: 25 additions & 0 deletions vault/logical_system_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -2641,6 +2641,31 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-resultant-acl"][0]),
HelpDescription: strings.TrimSpace(sysHelp["internal-ui-resultant-acl"][1]),
},
{
Pattern: "internal/ui/version",
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: "internal-ui",
OperationVerb: "read",
OperationSuffix: "version",
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{
Callback: b.pathInternalUIVersion,
Summary: "Backwards compatibility is not guaranteed for this API",

Choose a reason for hiding this comment

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

❓ I wonder why we just use the same summary message for multiple internal API endpoints, do you think it would be useful to include what this endpoint is for (even if it also says that it doesn't guarantee backwards compatibility)?

Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"version": {
Type: framework.TypeString,
Required: true,
},
},
}},
},
},
},
},
{
Pattern: "internal/counters/requests",
DisplayAttrs: &framework.DisplayAttributes{
Expand Down
6 changes: 6 additions & 0 deletions vault/policy_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ path "sys/internal/ui/resultant-acl" {
capabilities = ["read"]
}

# Allow a token to look up the Vault version. This path is not subject to
# redaction like the unauthenticated endpoints that provide the Vault version.
path "sys/internal/ui/version" {
capabilities = ["read"]
}

# Allow a token to renew a lease via lease_id in the request body; old path for
# old clients, new path for newer
path "sys/renew" {
Expand Down
3 changes: 0 additions & 3 deletions version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ func GetVersion() *VersionInfo {
if GitDescribe != "" {
ver = GitDescribe
}
if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
rel = "dev"
}
marcboudreau marked this conversation as resolved.
Show resolved Hide resolved

return &VersionInfo{
Revision: GitCommit,
Expand Down
111 changes: 111 additions & 0 deletions version/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package version

import (
"testing"

"github.com/stretchr/testify/assert"
)

func replaceVersion(v, vp string) func() {
origV := Version
origVP := VersionPrerelease

Version = v
VersionPrerelease = vp

return func() {
Version = origV
VersionPrerelease = origVP
}
}

func TestGetVersion(t *testing.T) {
// This test cannot be parallelized because it messes with some global
// variables that determine the version information.
restoreVersionFunc := replaceVersion("1.2.3", "")
defer restoreVersionFunc()

// Test the general case
vi := GetVersion()
assert.Equal(t, "1.2.3", vi.Version)
assert.Equal(t, "", vi.VersionPrerelease)
assert.Equal(t, "", vi.VersionMetadata)
assert.Equal(t, "", vi.Revision)
assert.Equal(t, "", vi.BuildDate)

// Test the git describe case
origGitDescribe := GitDescribe
GitDescribe = "git-describe"
vi = GetVersion()
assert.Equal(t, "git-describe", vi.Version)

GitDescribe = origGitDescribe
}

func TestVersionNumber(t *testing.T) {
// This test cannot be parallelized because it messes with some global
// variables that determine the version information.
restoreVersionFunc := replaceVersion("unknown", "unknown")
defer restoreVersionFunc()

// Test the unknown version case
vi := GetVersion()
assert.Equal(t, "(version unknown)", vi.VersionNumber())

replaceVersion("1.2.3", "")

// Test the pre-release case
vi = GetVersion()
vi.VersionPrerelease = "rc1"
assert.Equal(t, "1.2.3-rc1", vi.VersionNumber())

// Test the pre-release and metadata version case
vi.VersionMetadata = "ent"
assert.Equal(t, "1.2.3-rc1+ent", vi.VersionNumber())

// Test the metadata only version case
vi.VersionPrerelease = ""
assert.Equal(t, "1.2.3+ent", vi.VersionNumber())
}

func TestFullVersionNumber(t *testing.T) {
// This test cannot be parallelized because it messes with some global
// variables that determine the version information.
restoreVersionFunc := replaceVersion("unknown", "unknown")
defer restoreVersionFunc()

// Test the unknown version case
vi := GetVersion()
assert.Equal(t, "Vault (version unknown)", vi.FullVersionNumber(false))

// Test the no pre-release, metadata, revision, build date case
replaceVersion("1.2.3", "")
vi = GetVersion()
assert.Equal(t, "Vault v1.2.3", vi.FullVersionNumber(false))

// Test the pre-release case
vi.VersionPrerelease = "rc1"
assert.Equal(t, "Vault v1.2.3-rc1", vi.FullVersionNumber(false))

// Test the metadata case
vi.VersionPrerelease = ""
vi.VersionMetadata = "ent"
assert.Equal(t, "Vault v1.2.3+ent", vi.FullVersionNumber(false))

// Test the revision case
vi.VersionMetadata = ""
vi.Revision = "ab1234f"
assert.Equal(t, "Vault v1.2.3 (ab1234f)", vi.FullVersionNumber(true))

// Test the build date case
vi.BuildDate = "2023-10-20"
assert.Equal(t, "Vault v1.2.3, built 2023-10-20", vi.FullVersionNumber(false))

// Test the case where all of the things are set
vi.VersionPrerelease = "rc1"
vi.VersionMetadata = "ent"
assert.Equal(t, "Vault v1.2.3-rc1+ent (ab1234f), built 2023-10-20", vi.FullVersionNumber(true))
}
51 changes: 51 additions & 0 deletions website/content/api-docs/system/internal-ui-version.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
layout: api
page_title: /sys/internal/ui/version - HTTP API
description: >-
The `/sys/internal/ui/version` endpoint exposes the software version of Vault.
---

# `/sys/internal/ui/version`

The `/sys/internal/ui/version` endpoint exposes the Vault software version
so the Vault UI can display the information to logged in users.

Vault uses internal endpoints to provide information to the Vault UI
and/or Vault CLI. Internal endpoints are explicitly intended to support
Vault functionality, so we do not recommend them for general use
and do not guarantee backwards compatibility across versions.

## Get version

Return the current software version of Vault.

| Method | Path |
| :----- | :------------------------- |
| `GET` | `/sys/internal/ui/version` |

### Sample request

```shell-session
$ curl \
--header "X-Vault-Token: ..." \
--request GET \
http://127.0.0.1:8200/v1/sys/internal/ui/version
```

### Sample response

```json
{
"request_id": "d585b9be-9c6f-a05f-939b-490cf062ebbe",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"version": "1.16.0"
},
"wrap_info": null,
"warnings": null,
"auth": null,
"mount_type": "system"
}
```
4 changes: 4 additions & 0 deletions website/data/api-docs-nav-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,10 @@
"title": "<code>/sys/internal/ui/resultant-acl</code>",
"path": "system/internal-ui-resultant-acl"
},
{
"title": "<code>/sys/internal/ui/version</code>",
"path": "system/internal-ui-version"
},
{
"title": "<code>/sys/key-status</code>",
"path": "system/key-status"
Expand Down
Loading