hashicorp / hashicorp/terraform-plugin-codegen-openapi

Not properly mapping "read only" attribute to computed

Open
#235 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Go
Stars
91
Forks
20
Avg merge
2d 13h
Merged PRs (30d)
1

Description

### tfplugingen-openapi CLI version

v0.3.0

### OpenAPI Spec File

```YAML
Paths

"/console/v1/experiments/entity_property/{name}": {
"get": {
"summary": "Get Entity Property Source",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"description": "Name of entity property source",
"schema": {
"type": "string"
}
},
{
"name": "x-respect-review-settings",
"in": "header",
"description": "Optional header to respect review settings for mutation endpoints.",
"required": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Get Entity Property Source response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/EntityPropertySourceDto"
}
},
"example": {
"message": "Entity Property Source read successfully.",
"data": {
"name": "Location",
"description": "This is the the location description",
"tags": [

],
"sql": "SELECT * FROM shoppy-sales.setup.user_properties",
"timestampColumn": "timestamp",
"idTypeMapping": [
{
"statsigUnitID": "stableID",
"column": "user_id"
}
],
"timestampAsDay": true
}
}
},
"example": {
"message": "Entity Property Source read successfully.",
"data": {
"name": "Location",
"description": "This is the the location description",
"tags": [

],
"sql": "SELECT * FROM shoppy-sales.setup.user_properties",
"timestampColumn": "timestamp",
"idTypeMapping": [
{
"statsigUnitID": "stableID",
"column": "user_id"
}
],
"timestampAsDay": true
}
}
}
}
},
"400": {
"description": "Invalid request. Please check the request input and try again.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
400
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Request": {
"value": {
"status": 400,
"message": "Invalid request. Please check the request input and try again."
}
}
}
}
}
},
"401": {
"description": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
401
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Endpoint": {
"value": {
"status": 401,
"message": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx"
}
}
}
}
}
}
},
"tags": [
"Experiments (Warehouse Native)"
],
"security": [
{
"STATSIG-API-KEY": [

]
}
]
},
"post": {
"summary": "Post Entity Property Source",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"description": "name",
"schema": {
"type": "string"
}
},
{
"name": "x-respect-review-settings",
"in": "header",
"description": "Optional header to respect review settings for mutation endpoints.",
"required": false,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EntityPropertySourceQueryUpdateDto"
}
}
}
},
"responses": {
"200": {
"description": "Post Entity Property Source response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/EntityPropertySourceDto"
}
},
"example": {
"message": "Entity Property Sources updated successfully.",
"data": {
"name": "Location",
"description": "This is the the location description",
"tags": [

],
"sql": "SELECT * FROM shoppy-sales.setup.user_properties",
"timestampColumn": "",
"idTypeMapping": [
{
"statsigUnitID": "stableID",
"column": "user_id"
}
],
"timestampAsDay": true
}
}
},
"example": {
"message": "Entity Property Sources updated successfully.",
"data": {
"name": "Location",
"description": "This is the the location description",
"tags": [

],
"sql": "SELECT * FROM shoppy-sales.setup.user_properties",
"timestampColumn": "",
"idTypeMapping": [
{
"statsigUnitID": "stableID",
"column": "user_id"
}
],
"timestampAsDay": true
}
}
}
}
},
"400": {
"description": "Invalid request. Please check the request input and try again.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
400
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Request": {
"value": {
"status": 400,
"message": "Invalid request. Please check the request input and try again."
}
}
}
}
}
},
"401": {
"description": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
401
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Endpoint": {
"value": {
"status": 401,
"message": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx"
}
}
}
}
}
},
"404": {
"description": "Not Found. The requested resource could not be found.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
404
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Not Found": {
"value": {
"status": 404,
"message": "Not Found. The requested resource could not be found."
}
}
}
}
}
}
},
"tags": [
"Experiments (Warehouse Native)"
],
"security": [
{
"STATSIG-API-KEY": [

]
}
]
},
"patch": {
"summary": "Patch Entity Property Source",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"description": "Name of entity property source",
"schema": {
"type": "string"
}
},
{
"name": "x-respect-review-settings",
"in": "header",
"description": "Optional header to respect review settings for mutation endpoints.",
"required": false,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EntityPropertySourcePartialUpdateDto"
}
}
}
},
"responses": {
"200": {
"description": "Patch Entity Property Source response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/EntityPropertySourceDto"
}
},
"example": {
"message": "Entity Property Source updated successfully",
"data": {
"name": "Location",
"description": "This is the the location description",
"tags": [

],
"sql": "SELECT * FROM shoppy-sales.setup.user_properties",
"timestampColumn": "timestamp",
"idTypeMapping": [
{
"statsigUnitID": "stableID",
"column": "user_id"
}
],
"timestampAsDay": true
}
}
},
"example": {
"message": "Entity Property Source updated successfully",
"data": {
"name": "Location",
"description": "This is the the location description",
"tags": [

],
"sql": "SELECT * FROM shoppy-sales.setup.user_properties",
"timestampColumn": "timestamp",
"idTypeMapping": [
{
"statsigUnitID": "stableID",
"column": "user_id"
}
],
"timestampAsDay": true
}
}
}
}
},
"400": {
"description": "Invalid request. Please check the request input and try again.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
400
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Request": {
"value": {
"status": 400,
"message": "Invalid request. Please check the request input and try again."
}
}
}
}
}
},
"401": {
"description": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
401
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Endpoint": {
"value": {
"status": 401,
"message": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx"
}
}
}
}
}
},
"404": {
"description": "Not Found. The requested resource could not be found.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
404
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Not Found": {
"value": {
"status": 404,
"message": "Not Found. The requested resource could not be found."
}
}
}
}
}
}
},
"tags": [
"Experiments (Warehouse Native)"
],
"security": [
{
"STATSIG-API-KEY": [

]
}
]
},
"delete": {
"summary": "Delete Entity Property Source",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"description": "name",
"schema": {
"type": "string"
}
},
{
"name": "x-respect-review-settings",
"in": "header",
"description": "Optional header to respect review settings for mutation endpoints.",
"required": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Delete Entity Property Source response",
"content": {
"application/json": {
"schema": {
"properties": {
"message": {
"type": "string"
}
},
"example": {
"message": "Entity property source deleted successfully."
}
},
"example": {
"message": "Entity property source deleted successfully."
}
}
}
},
"400": {
"description": "Invalid request. Please check the request input and try again.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
400
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Request": {
"value": {
"status": 400,
"message": "Invalid request. Please check the request input and try again."
}
}
}
}
}
},
"401": {
"description": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
401
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Invalid Endpoint": {
"value": {
"status": 401,
"message": "This endpoint only accepts an active CONSOLE key, but an invalid key was sent. Key: console-xxxXXXxxxXXXxxx"
}
}
}
}
}
},
"404": {
"description": "Not Found. The requested resource could not be found.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"enum": [
404
]
},
"message": {
"type": "string"
}
},
"required": [
"status",
"message"
]
},
"examples": {
"Not Found": {
"value": {
"status": 404,
"message": "Not Found. The requested resource could not be found."
}
}
}
}
}
}
},
"tags": [
"Experiments (Warehouse Native)"
],
"security": [
{
"STATSIG-API-KEY": [

]
}
]
}
}

Component schemas

"EntityPropertySourceDto": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Unique identifier for the entity property source."
},
"description": {
"type": "string",
"description": "Detailed context and purpose of the entity property source."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Tags for categorization and search."
},
"sql": {
"type": "string",
"description": "SQL query defining the data source."
},
"timestampColumn": {
"type": "string",
"description": "Optional column name for timestamp."
},
"timestampAsDay": {
"type": "boolean",
"description": "Indicates if the timestamp is treated as a day."
},
"idTypeMapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"statsigUnitID": {
"type": "string",
"description": "ID for the Statsig unit."
},
"column": {
"type": "string",
"description": "Column name linked to the ID."
}
},
"required": [
"statsigUnitID",
"column"
]
},
"description": "Mappings of Statsig units to their columns."
},
"isReadOnly": {
"type": "boolean",
"description": "Specifies if the source can only be edited via the Console API."
},
"owner": {
"type": "object",
"properties": {
"ownerID": {
"type": "string",
"description": "ID of the owner",
"example": "abc123"
},
"ownerType": {
"type": "string",
"description": "Type of the owner (e.g., SDK_KEY or USER)",
"example": "USER"
},
"ownerName": {
"type": "string",
"description": "The name of the owner. This field is optional.",
"example": "John Doe"
},
"ownerEmail": {
"type": "string",
"description": "The email of the owner. This field is optional."
}
},
"description": "Schema for owner data including ID, type, name. Note that if Entity is created by CONSOLE API, owner will be undefined.",
"example": {
"ownerID": "user123",
"ownerType": "USER",
"ownerName": "John Doe",
"ownerEmail": "owner123@test.com"
},
"nullable": true,
"readonly": true
}
},
"required": [
"name",
"description",
"tags",
"sql",
"idTypeMapping"
]
},
"EntityPropertySourceCreationDto": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Unique identifier for the entity property source."
},
"description": {
"type": "string",
"description": "Optional detailed context for the entity property source."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional tags for categorization."
},
"sql": {
"type": "string",
"description": "SQL query defining the data source."
},
"timestampColumn": {
"type": "string",
"description": "Optional column name for timestamp."
},
"timestampAsDay": {
"type": "boolean",
"description": "Indicates if the timestamp is treated as a day."
},
"idTypeMapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"statsigUnitID": {
"type": "string",
"description": "ID for the Statsig unit."
},
"column": {
"type": "string",
"description": "Column name linked to the ID."
}
},
"required": [
"statsigUnitID",
"column"
]
},
"description": "Mappings of Statsig units to their columns."
},
"isReadOnly": {
"type": "boolean",
"description": "Specifies if the source can only be edited via the Console API."
}
},
"required": [
"name",
"sql",
"idTypeMapping"
]
},
"EntityPropertySourcePartialUpdateDto": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Unique identifier for the entity property source."
},
"description": {
"type": "string",
"description": "Detailed context and purpose of the entity property source."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Tags for categorization and search."
},
"sql": {
"readOnly": true,
"description": "SQL query defining the data source"
},
"timestampColumn": {
"type": "string",
"description": "Optional column name for timestamp."
},
"timestampAsDay": {
"type": "boolean",
"description": "Indicates if the timestamp is treated as a day."
},
"idTypeMapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"statsigUnitID": {
"type": "string",
"description": "ID for the Statsig unit."
},
"column": {
"type": "string",
"description": "Column name linked to the ID."
}
},
"required": [
"statsigUnitID",
"column"
]
},
"description": "Mappings of Statsig units to their columns."
},
"isReadOnly": {
"type": "boolean",
"description": "Specifies if the source can only be edited via the Console API."
}
}
},
"EntityPropertySourceQueryUpdateDto": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Optional new name for the entity property source."
},
"description": {
"type": "string",
"description": "Optional updated context for the entity property source."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional updated tags for categorization."
},
"sql": {
"type": "string",
"description": "SQL query defining the data source."
},
"timestampColumn": {
"type": "string",
"description": "Optional column name for timestamp."
},
"timestampAsDay": {
"type": "boolean",
"description": "Indicates if the timestamp is treated as a day."
},
"idTypeMapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"statsigUnitID": {
"type": "string",
"description": "ID for the Statsig unit."
},
"column": {
"type": "string",
"description": "Column name linked to the ID."
}
},
"required": [
"statsigUnitID",
"column"
]
},
"description": "Mappings of Statsig units to their columns."
},
"isReadOnly": {
"type": "boolean",
"description": "Specifies if the source can only be edited via the Console API."
}
},
"required": [
"sql",
"idTypeMapping"
]
}
```

### Generator Config

```YAML
entity_property:
read:
path: /console/v1/experiments/entity_property/{name}
method: GET
create:
path: /console/v1/experiments/entity_properties
method: POST
update:
path: /console/v1/experiments/entity_property/{name}
method: POST
delete:
path: /console/v1/experiments/entity_property/{name}
method: DELETE
schema:
ignores:
- message
- data
```

### Expected Behavior

Expected the generated resource spec in `provider_code_spec.json` to include the read-only attribute `owner` with `computed_optional_required` equal to `computed`. According to the following from `DESIGN.md`
>If the field is only present in a schema other than the create operation requestBody, then the field will be mapped as computed.

```json
{
"name": "owner",
"single_nested": {
"computed_optional_required": "computed",
"attributes": [
{
"name": "owner_email",
"string": {
"computed_optional_required": "computed_optional",
"description": "The email of the owner. This field is optional."
}
},
{
"name": "owner_id",
"string": {
"computed_optional_required": "computed_optional",
"description": "ID of the owner"
}
},
{
"name": "owner_name",
"string": {
"computed_optional_required": "computed_optional",
"description": "The name of the owner. This field is optional."
}
},
{
"name": "owner_type",
"string": {
"computed_optional_required": "computed_optional",
"description": "Type of the owner (e.g., SDK_KEY or USER)"
}
}
],
"description": "Schema for owner data including ID, type, name. Note that if Entity is created by CONSOLE API, owner will be undefined."
}
},
```

### Actual Behavior

`owner` is missing in the resource spec
```json
{
"name": "entity_property",
"schema": {
"attributes": [
{
"name": "description",
"string": {
"computed_optional_required": "computed_optional",
"description": "Optional detailed context for the entity property source."
}
},
{
"name": "id_type_mapping",
"list_nested": {
"computed_optional_required": "required",
"nested_object": {
"attributes": [
{
"name": "column",
"string": {
"computed_optional_required": "required",
"description": "Column name linked to the ID."
}
},
{
"name": "statsig_unit_id",
"string": {
"computed_optional_required": "required",
"description": "ID for the Statsig unit."
}
}
]
},
"description": "Mappings of Statsig units to their columns."
}
},
{
"name": "is_read_only",
"bool": {
"computed_optional_required": "computed_optional",
"description": "Specifies if the source can only be edited via the Console API."
}
},
{
"name": "name",
"string": {
"computed_optional_required": "required",
"description": "Unique identifier for the entity property source."
}
},
{
"name": "sql",
"string": {
"computed_optional_required": "required",
"description": "SQL query defining the data source."
}
},
{
"name": "tags",
"list": {
"computed_optional_required": "computed_optional",
"element_type": {
"string": {

}
},
"description": "Optional tags for categorization."
}
},
{
"name": "timestamp_as_day",
"bool": {
"computed_optional_required": "computed_optional",
"description": "Indicates if the timestamp is treated as a day."
}
},
{
"name": "timestamp_column",
"string": {
"computed_optional_required": "computed_optional",
"description": "Optional column name for timestamp."
}
}
]
}
},

```

### Additional Information

_No response_

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.