Skip to content
Open
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
4 changes: 4 additions & 0 deletions CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ With `-o json`, the same error is JSON on stderr:
| `project_not_found` | The project doesn't exist or isn't visible (404) |
| `project_type_not_supported` | A project of another product was passed to a `secrets-manager` command |
| `environment_not_found` | The environment slug doesn't exist in the project (404) |
| `environment_exists` | `environments create` (or `update --slug`) with a slug an active environment has. Nothing is written |
| `environment_pending_deletion` | The slug belongs to an environment pending deletion, which keeps it until the grace period ends. Suggests `delete --force` |
| `invalid_flag_value` | A flag was given a value the command can't use, such as an empty `--name`. Nothing is sent |
| `project_required` | A delete ran without `--projectId`. Deletes never use `INFISICAL_PROJECT_ID` or `.infisical.yaml` |
| `secret_exists` | `secrets create` on a key that exists. Nothing is written |
| `secret_not_found` | `secrets update` on a key that doesn't exist. Nothing is written |
| `folder_not_found` | `folders get <name>` for a folder that doesn't exist |
Expand Down
108 changes: 108 additions & 0 deletions packages/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ const (
operationCallListProjects = "CallListProjects"
operationCallGetProject = "CallGetProject"
operationCallCreateProject = "CallCreateProject"
operationCallGetProjectEnvironments = "CallGetProjectEnvironments"
operationCallGetEnvironmentBySlug = "CallGetEnvironmentBySlug"
operationCallCreateEnvironment = "CallCreateEnvironment"
operationCallUpdateEnvironment = "CallUpdateEnvironment"
operationCallDeleteEnvironment = "CallDeleteEnvironment"
operationCallIsAuthenticated = "CallIsAuthenticated"
operationCallGetNewAccessTokenWithRefreshToken = "CallGetNewAccessTokenWithRefreshToken"
operationCallGetFoldersV1 = "CallGetFoldersV1"
Expand Down Expand Up @@ -421,6 +426,109 @@ func CallCreateProject(httpClient *resty.Client, request CreateProjectRequest) (
return createResponse.Project, nil
}

func CallGetProjectEnvironments(httpClient *resty.Client, projectID string) (ProjectEnvironments, error) {
var projectResponse GetProjectEnvironmentsResponse
response, err := httpClient.
R().
SetResult(&projectResponse).
SetHeader("User-Agent", USER_AGENT).
Get(fmt.Sprintf("%v/v1/projects/%s", config.INFISICAL_URL, url.PathEscape(projectID)))

if err != nil {
return ProjectEnvironments{}, NewGenericRequestError(operationCallGetProjectEnvironments, err)
}

if response.IsError() {
return ProjectEnvironments{}, NewAPIErrorWithResponse(operationCallGetProjectEnvironments, response, nil)
}

return projectResponse.Project, nil
}

// CallGetEnvironmentBySlug finds an active environment; one pending deletion is a 404.
func CallGetEnvironmentBySlug(httpClient *resty.Client, projectID, slug string) (Environment, error) {
var environmentResponse EnvironmentResponse
response, err := httpClient.
R().
SetResult(&environmentResponse).
SetHeader("User-Agent", USER_AGENT).
Get(fmt.Sprintf("%v/v1/projects/%s/environments/slug/%s", config.INFISICAL_URL, url.PathEscape(projectID), url.PathEscape(slug)))

if err != nil {
return Environment{}, NewGenericRequestError(operationCallGetEnvironmentBySlug, err)
}

if response.IsError() {
return Environment{}, NewAPIErrorWithResponse(operationCallGetEnvironmentBySlug, response, nil)
}

return environmentResponse.Environment, nil
}

func CallCreateEnvironment(httpClient *resty.Client, projectID string, request CreateEnvironmentRequest) (Environment, error) {
var environmentResponse EnvironmentResponse
response, err := httpClient.
R().
SetBody(request).
SetResult(&environmentResponse).
SetHeader("User-Agent", USER_AGENT).
Post(fmt.Sprintf("%v/v1/projects/%s/environments", config.INFISICAL_URL, url.PathEscape(projectID)))

if err != nil {
return Environment{}, NewGenericRequestError(operationCallCreateEnvironment, err)
}

if response.IsError() {
return Environment{}, NewAPIErrorWithResponse(operationCallCreateEnvironment, response, nil)
}

return environmentResponse.Environment, nil
}

func CallUpdateEnvironment(httpClient *resty.Client, projectID, environmentID string, request UpdateEnvironmentRequest) (Environment, error) {
var environmentResponse EnvironmentResponse
response, err := httpClient.
R().
SetBody(request).
SetResult(&environmentResponse).
SetHeader("User-Agent", USER_AGENT).
Patch(fmt.Sprintf("%v/v1/projects/%s/environments/%s", config.INFISICAL_URL, url.PathEscape(projectID), url.PathEscape(environmentID)))

if err != nil {
return Environment{}, NewGenericRequestError(operationCallUpdateEnvironment, err)
}

if response.IsError() {
return Environment{}, NewAPIErrorWithResponse(operationCallUpdateEnvironment, response, nil)
}

return environmentResponse.Environment, nil
}

// CallDeleteEnvironment soft-deletes the environment, or permanently deletes it with hardDelete. Backends
// without soft delete ignore hardDelete and always delete permanently; their response has no deleteAfter.
func CallDeleteEnvironment(httpClient *resty.Client, projectID, environmentID string, hardDelete bool) (Environment, error) {
var environmentResponse EnvironmentResponse
request := httpClient.
R().
SetResult(&environmentResponse).
SetHeader("User-Agent", USER_AGENT)
if hardDelete {
request.SetQueryParam("hardDelete", "true")
}
response, err := request.Delete(fmt.Sprintf("%v/v1/projects/%s/environments/%s", config.INFISICAL_URL, url.PathEscape(projectID), url.PathEscape(environmentID)))

if err != nil {
return Environment{}, NewGenericRequestError(operationCallDeleteEnvironment, err)
}

if response.IsError() {
return Environment{}, NewAPIErrorWithResponse(operationCallDeleteEnvironment, response, nil)
}

return environmentResponse.Environment, nil
}

func CallGetProjectBySlug(httpClient *resty.Client, slug string) (Project, error) {
var projectResponse GetProjectBySlugResponse
response, err := httpClient.
Expand Down
44 changes: 44 additions & 0 deletions packages/api/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,50 @@ type CreateProjectResponse struct {
Project ProjectDetails `json:"project"`
}

// Environment is a project environment as the /v1/projects/:projectId/environments endpoints return
// it. DeleteAfter is set once it is soft-deleted, and is when it will be permanently deleted.
type Environment struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Position int `json:"position"`
ProjectID string `json:"projectId"`
DeleteAfter string `json:"deleteAfter,omitempty"`
}

type EnvironmentResponse struct {
Environment Environment `json:"environment"`
}

type DeletedEnvironment struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
DeleteAfter string `json:"deleteAfter"`
}

// ProjectEnvironments is a project with its active environments, in position order, and the ones
// pending deletion. It is decoded from the same response as ProjectDetails, which leaves out
// deletedEnvironments so `projects get -o json` keeps its shape.
type ProjectEnvironments struct {
ProjectDetails
DeletedEnvironments []DeletedEnvironment `json:"deletedEnvironments"`
}

type GetProjectEnvironmentsResponse struct {
Project ProjectEnvironments `json:"project"`
}

type CreateEnvironmentRequest struct {
Name string `json:"name"`
Slug string `json:"slug"`
}

type UpdateEnvironmentRequest struct {
Name *string `json:"name,omitempty"`
Slug *string `json:"slug,omitempty"`
}

type RawSecret struct {
SecretKey string `json:"secretKey,omitempty"`
SecretValue string `json:"secretValue,omitempty"`
Expand Down
Loading
Loading