Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ NOTES:
left out of the configuration keeps the value the endpoint already has.
* `quicknode_endpoint.ip_custom_header` names the header an endpoint behind a proxy
reads the caller's IP address from.
* Allowlist entries are imported by value, as `652052/203.0.113.7`.
* Allowlist entries are imported by value, as `123456/203.0.113.7`.
* Adding an allowlist entry while its toggle is disabled warns and succeeds, so an
allowlist can be built before enforcement is turned on.
* `quicknode_endpoint.label` cannot be cleared once set, so removing the attribute
* `quicknode_endpoint.label` cannot be cleared once set. Removing the attribute
leaves the endpoint's label in place.
* `quicknode_endpoint_jwt` takes `kid` as an input. The Admin API requires it when
the signing key is registered.
* `quicknode_endpoint_jwt.kid` is required, and matches the `kid` header of the
tokens signed with the corresponding private key.
2 changes: 1 addition & 1 deletion docs/index.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_domain_mask.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_ip.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_jwt.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_method_rate_limit.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_rate_limits.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_referrer.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_request_filter.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/resources/endpoint_token.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Import by the domain itself, as "<endpoint id>/<domain>".
terraform import quicknode_endpoint_domain_mask.rpc 652052/rpc.example.com
terraform import quicknode_endpoint_domain_mask.rpc 123456/rpc.example.com
2 changes: 1 addition & 1 deletion examples/resources/quicknode_endpoint_ip/import.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Import by the address itself, as "<endpoint id>/<ip>".
terraform import quicknode_endpoint_ip.office 652052/203.0.113.7
terraform import quicknode_endpoint_ip.office 123456/203.0.113.7
2 changes: 1 addition & 1 deletion examples/resources/quicknode_endpoint_jwt/import.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Import by the key's name, as "<endpoint id>/<name>".
terraform import quicknode_endpoint_jwt.signer 652052/signer
terraform import quicknode_endpoint_jwt.signer 123456/signer
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# A limiter has no natural name, so it is imported by id, as
# "<endpoint id>/<limiter id>".
terraform import quicknode_endpoint_method_rate_limit.heavy_reads 652052/a1b2c3d4-5e6f-7890-abcd-ef1234567890
terraform import quicknode_endpoint_method_rate_limit.heavy_reads 123456/a1b2c3d4-5e6f-7890-abcd-ef1234567890
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Rate limits belong to the endpoint, so the address is just the endpoint id.
terraform import quicknode_endpoint_rate_limits.api 652052
terraform import quicknode_endpoint_rate_limits.api 123456
2 changes: 1 addition & 1 deletion examples/resources/quicknode_endpoint_referrer/import.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Import by the referrer itself, as "<endpoint id>/<referrer>".
terraform import quicknode_endpoint_referrer.app 652052/https://app.example.com
terraform import quicknode_endpoint_referrer.app 123456/https://app.example.com
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# A filter has no natural name, so it is imported by id, as
# "<endpoint id>/<filter id>". Read the ids from the endpoint's security
# settings in the Quicknode dashboard.
terraform import quicknode_endpoint_request_filter.read_only 652052/f1e2d3c4-5b6a-7890-abcd-ef1234567890
terraform import quicknode_endpoint_request_filter.read_only 123456/f1e2d3c4-5b6a-7890-abcd-ef1234567890
2 changes: 1 addition & 1 deletion examples/resources/quicknode_endpoint_token/import.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Tokens are imported by id, as "<endpoint id>/<token id>", which keeps the
# credential out of shell history.
terraform import quicknode_endpoint_token.indexer 652052/d3312bd2-c1a2-4d89-865f-11c99fa3863a
terraform import quicknode_endpoint_token.indexer 123456/e5d4c3b2-a1f0-4876-9432-10fedcba9876
12 changes: 6 additions & 6 deletions internal/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ func TestRedactEndpointURL(t *testing.T) {
}{
{
name: "token followed by a chain suffix",
raw: "https://polished-damp-grass.hype-testnet.quiknode.pro/abc123/evm",
want: "https://polished-damp-grass.hype-testnet.quiknode.pro/TOKEN/evm",
raw: "https://example-name.hype-testnet.quiknode.pro/abc123/evm",
want: "https://example-name.hype-testnet.quiknode.pro/TOKEN/evm",
},
{
name: "token with no suffix",
Expand All @@ -23,8 +23,8 @@ func TestRedactEndpointURL(t *testing.T) {
},
{
name: "trailing slash after the token",
raw: "https://frosty-capable-pallet.btc.quiknode.pro/abc123/",
want: "https://frosty-capable-pallet.btc.quiknode.pro/TOKEN/",
raw: "https://example-name.btc.quiknode.pro/abc123/",
want: "https://example-name.btc.quiknode.pro/TOKEN/",
},
{
name: "websocket scheme",
Expand Down Expand Up @@ -57,8 +57,8 @@ func TestRedactEndpointURL(t *testing.T) {
// suffix the chain appends after the token.
func TestRedactedURLKeepsItsShape(t *testing.T) {
for _, raw := range []string{
"https://polished-damp-grass.hype-testnet.quiknode.pro/abc123/evm",
"https://frosty-capable-pallet.btc.quiknode.pro/abc123/",
"https://example-name.hype-testnet.quiknode.pro/abc123/evm",
"https://example-name.btc.quiknode.pro/abc123/",
"wss://example-name.quiknode.pro/abc123",
} {
redacted := RedactEndpointURL(raw)
Expand Down
38 changes: 19 additions & 19 deletions internal/client/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ import (

// hypeEndpointBody mirrors a live GET /v0/endpoints/{id} response for a chain
// that appends a path suffix after the token. The token is fabricated.
const hypeEndpointBody = `{"data":{"id":"652052","label":null,"chain":"hype","network":"hype-testnet",
"http_url":"https://polished-damp-grass.hype-testnet.quiknode.pro/TOKENVALUE/evm",
"wss_url":"wss://polished-damp-grass.hype-testnet.quiknode.pro/TOKENVALUE/evm",
const hypeEndpointBody = `{"data":{"id":"123456","label":null,"chain":"hype","network":"hype-testnet",
"http_url":"https://example-name.hype-testnet.quiknode.pro/TOKENVALUE/evm",
"wss_url":"wss://example-name.hype-testnet.quiknode.pro/TOKENVALUE/evm",
"security":{"options":{"tokens":true,"cors":true},
"tokens":[{"id":"d3312bd2-c1a2-4d89-865f-11c99fa3863a","token":"TOKENVALUE"}],
"tokens":[{"id":"e5d4c3b2-a1f0-4876-9432-10fedcba9876","token":"TOKENVALUE"}],
"jwts":null,"referrers":null,"domain_masks":null,"ips":null,"request_filters":null},
"status":"active","rate_limits":{"rate_limit_by_ip":false,"account":-1,"rps":-1,"rpd":-1,"rpm":-1},
"tags":[{"tag_id":7,"label":"prod"}],"is_multichain":false}}`

// bitcoinEndpointBody mirrors a live response for a chain with no WebSocket
// support and no path suffix.
const bitcoinEndpointBody = `{"data":{"id":"613071","label":"ledger","chain":"btc","network":"btc",
"http_url":"https://frosty-capable-pallet.btc.quiknode.pro/TOKENVALUE/","wss_url":null,
const bitcoinEndpointBody = `{"data":{"id":"123457","label":"ledger","chain":"btc","network":"btc",
"http_url":"https://example-name.btc.quiknode.pro/TOKENVALUE/","wss_url":null,
"security":{"options":{"tokens":true},"tokens":[{"id":"abc","token":"TOKENVALUE"}]},
"status":"paused","tags":[],"is_multichain":false}}`

Expand All @@ -47,26 +47,26 @@ func newTestClient(t *testing.T, body string) *Client {
}

func TestGetEndpointWithPathSuffix(t *testing.T) {
endpoint, err := newTestClient(t, hypeEndpointBody).GetEndpoint(context.Background(), "652052")
endpoint, err := newTestClient(t, hypeEndpointBody).GetEndpoint(context.Background(), "123456")
if err != nil {
t.Fatalf("GetEndpoint: %v", err)
}

const wantWorking = "https://polished-damp-grass.hype-testnet.quiknode.pro/TOKENVALUE/evm"
const wantWorking = "https://example-name.hype-testnet.quiknode.pro/TOKENVALUE/evm"
if endpoint.HTTPURLWithToken != wantWorking {
t.Errorf("HTTPURLWithToken = %q, want %q", endpoint.HTTPURLWithToken, wantWorking)
}
if endpoint.WSSURLWithToken != "wss://polished-damp-grass.hype-testnet.quiknode.pro/TOKENVALUE/evm" {
if endpoint.WSSURLWithToken != "wss://example-name.hype-testnet.quiknode.pro/TOKENVALUE/evm" {
t.Errorf("WSSURLWithToken = %q", endpoint.WSSURLWithToken)
}
if endpoint.SafeWSSURL != "wss://polished-damp-grass.hype-testnet.quiknode.pro/TOKEN/evm" {
if endpoint.SafeWSSURL != "wss://example-name.hype-testnet.quiknode.pro/TOKEN/evm" {
t.Errorf("SafeWSSURL = %q", endpoint.SafeWSSURL)
}

// The redacted URL keeps the real one's shape, so substituting a token
// reproduces it exactly. That is what the placeholder buys over cutting
// the token out: this chain puts a suffix after it.
const wantRedacted = "https://polished-damp-grass.hype-testnet.quiknode.pro/TOKEN/evm"
const wantRedacted = "https://example-name.hype-testnet.quiknode.pro/TOKEN/evm"
if endpoint.SafeHTTPURL != wantRedacted {
t.Errorf("SafeHTTPURL = %q, want %q", endpoint.SafeHTTPURL, wantRedacted)
}
Expand All @@ -86,18 +86,18 @@ func TestGetEndpointWithPathSuffix(t *testing.T) {
}

func TestGetEndpointWithoutWebsocket(t *testing.T) {
endpoint, err := newTestClient(t, bitcoinEndpointBody).GetEndpoint(context.Background(), "613071")
endpoint, err := newTestClient(t, bitcoinEndpointBody).GetEndpoint(context.Background(), "123457")
if err != nil {
t.Fatalf("GetEndpoint: %v", err)
}

if endpoint.SafeWSSURL != "" || endpoint.WSSURLWithToken != "" {
t.Errorf("SafeWSSURL = %q, WSSURLWithToken = %q, want both empty", endpoint.SafeWSSURL, endpoint.WSSURLWithToken)
}
if endpoint.HTTPURLWithToken != "https://frosty-capable-pallet.btc.quiknode.pro/TOKENVALUE/" {
if endpoint.HTTPURLWithToken != "https://example-name.btc.quiknode.pro/TOKENVALUE/" {
t.Errorf("HTTPURLWithToken = %q", endpoint.HTTPURLWithToken)
}
if endpoint.SafeHTTPURL != "https://frosty-capable-pallet.btc.quiknode.pro/TOKEN/" {
if endpoint.SafeHTTPURL != "https://example-name.btc.quiknode.pro/TOKEN/" {
t.Errorf("SafeHTTPURL = %q", endpoint.SafeHTTPURL)
}
if endpoint.Status != "paused" || endpoint.Label != "ledger" {
Expand All @@ -116,19 +116,19 @@ func TestGetEndpointRejectsEnvelopeError(t *testing.T) {
// liveEndpointBody is a verbatim GET /v0/endpoints/{id} response with the token
// replaced. It carries ipCustomHeader and responseLogging, which the published
// spec either mistypes or omits.
const liveEndpointBody = `{"data":{"id":"652052","label":null,"chain":"hype","network":"hype-testnet",` +
`"http_url":"https://polished-damp-grass.hype-testnet.quiknode.pro/TOKENVALUE/evm",` +
`"wss_url":"wss://polished-damp-grass.hype-testnet.quiknode.pro/TOKENVALUE/evm",` +
const liveEndpointBody = `{"data":{"id":"123456","label":null,"chain":"hype","network":"hype-testnet",` +
`"http_url":"https://example-name.hype-testnet.quiknode.pro/TOKENVALUE/evm",` +
`"wss_url":"wss://example-name.hype-testnet.quiknode.pro/TOKENVALUE/evm",` +
`"security":{"options":{"tokens":true,"referrers":false,"jwts":false,"ips":false,` +
`"domainMasks":false,"hsts":false,"cors":true,"responseLogging":true,` +
`"requestFilters":false,"ipCustomHeader":{"value":null}},` +
`"tokens":[{"id":"d3312bd2-c1a2-4d89-865f-11c99fa3863a","token":"TOKENVALUE"}],` +
`"tokens":[{"id":"e5d4c3b2-a1f0-4876-9432-10fedcba9876","token":"TOKENVALUE"}],` +
`"jwts":null,"referrers":null,"domain_masks":null,"ips":null,"request_filters":null},` +
`"status":"active","rate_limits":{"rate_limit_by_ip":false,"account":-1,"rps":-1,"rpd":-1,"rpm":-1},` +
`"tags":[],"is_multichain":false}}`

func TestGetEndpointDecodesLiveBody(t *testing.T) {
endpoint, err := newTestClient(t, liveEndpointBody).GetEndpoint(context.Background(), "652052")
endpoint, err := newTestClient(t, liveEndpointBody).GetEndpoint(context.Background(), "123456")
if err != nil {
t.Fatalf("GetEndpoint on a verbatim live body: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/jwt_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func (r *jwtResource) ImportState(ctx context.Context, req resource.ImportStateR
if !found || endpointID == "" || name == "" {
resp.Diagnostics.AddError(
"Unexpected import address",
fmt.Sprintf("Import a JWT signing key as \"<endpoint id>/<name>\", for example \"652052/signer\". Got %q.", req.ID),
fmt.Sprintf("Import a JWT signing key as \"<endpoint id>/<name>\", for example \"123456/signer\". Got %q.", req.ID),
)
return
}
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/method_rate_limit_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func (r *methodRateLimitResource) ImportState(ctx context.Context, req resource.
if !found || endpointID == "" || limiterID == "" {
resp.Diagnostics.AddError(
"Unexpected import address",
fmt.Sprintf("Import a method rate limit as \"<endpoint id>/<limiter id>\", for example \"652052/a1b2c3d4-...\". Got %q.", req.ID),
fmt.Sprintf("Import a method rate limit as \"<endpoint id>/<limiter id>\", for example \"123456/a1b2c3d4-...\". Got %q.", req.ID),
)
return
}
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/request_filter_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (r *requestFilterResource) ImportState(ctx context.Context, req resource.Im
if !found || endpointID == "" || filterID == "" {
resp.Diagnostics.AddError(
"Unexpected import address",
fmt.Sprintf("Import a request filter as \"<endpoint id>/<filter id>\", for example \"652052/f1e2d3c4-...\". Got %q.", req.ID),
fmt.Sprintf("Import a request filter as \"<endpoint id>/<filter id>\", for example \"123456/f1e2d3c4-...\". Got %q.", req.ID),
)
return
}
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/security_entry_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func (r *securityEntryResource) ImportState(ctx context.Context, req resource.Im
if !found || endpointID == "" || value == "" {
resp.Diagnostics.AddError(
"Unexpected import address",
fmt.Sprintf("Import a %s as \"<endpoint id>/<%s>\", for example \"652052/%s\". Got %q.", r.kind.noun, r.kind.attribute, importExample(r.kind.attribute), req.ID),
fmt.Sprintf("Import a %s as \"<endpoint id>/<%s>\", for example \"123456/%s\". Got %q.", r.kind.noun, r.kind.attribute, importExample(r.kind.attribute), req.ID),
)
return
}
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/token_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func (r *endpointTokenResource) ImportState(ctx context.Context, req resource.Im
if !found || endpointID == "" || tokenID == "" {
resp.Diagnostics.AddError(
"Unexpected import address",
fmt.Sprintf("Import an endpoint token as \"<endpoint id>/<token id>\", for example \"652052/d3312bd2-...\". Got %q.", req.ID),
fmt.Sprintf("Import an endpoint token as \"<endpoint id>/<token id>\", for example \"123456/e5d4c3b2-...\". Got %q.", req.ID),
)
return
}
Expand Down
2 changes: 1 addition & 1 deletion templates/index.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Endpoints expose both forms:
The safe form carries the literal `TOKEN` where the credential belongs:

```
https://polished-damp-grass.hype-testnet.quiknode.pro/TOKEN/evm
https://example-name.hype-testnet.quiknode.pro/TOKEN/evm
```

It keeps the real URL's shape, so substituting a token reproduces a working
Expand Down
Loading