ballerina-lang
ballerina-lang copied to clipboard
Identify special field types in the ballerina records for UI generation
Description:
ballerina/http ballerinax/mysql clients initialization may require some sensitive data such as clientId, clientSecret, password, path, etc. The type of these fields defined as strings.
public type RefreshTokenGrantConfig record {|
string refreshUrl;
string refreshToken;
string clientId;
string clientSecret;
public type ClientSecureSocket record {|
boolean enable = true;
crypto:TrustStore|string cert?;
crypto:KeyStore|CertKey key?;
public type KeyStore record {|
string path;
string password;
|};
Describe your problem(s) When we want to generate UI controls for entering values for these fields, the possible control is a text box. Is it possible to introduce an annotation pattern to describe the data? For example, clientSecret should mask value, and the path should be a file upload, etc. @shafreenAnfar @daneshk thoughts?
Describe your solution(s)
Related Issues (optional):
Suggested Labels (optional):
Suggested Assignees (optional):
@shafreenAnfar @hasithaa @hevayo This improvement is essential to provide a secure deployment option in Choreo. Inability to detect which configurable is sensitive or not, causes us to ask it from the user which is sort of not optimal in Ballerina context but in non-ballerina apps. Can we get an update so that we can plan accordingly?
Can't we use @display annotation here, with additional meta data? Each stdlib module has to follow the same convention.
+1. We'll come up with additional metadata and discuss it here to finalize them.
@hasithaa, I checked the @display definition.
# Denotes general-purpose metadata to customize how Ballerina symbols are displayed in a UI environment.
public const annotation record {
# label for the Ballerina construct
string label;
# icon path relative to module's resource directory
string iconPath?;
} display on source type, source class,
source function, source return, source parameter, source field, source listener,
source var, source const, source annotation, source service;
It allows only label and iconPath as metadata. label is required. We cannot define anything custom. Would it require some change from the Ballerina?
@indikasampath2000 But the record is open, you can have additional metadata called, kind/type, etc.. e.g.:
type SomeConfig record {
string username;
@display {
label: "auth token",
kind: "password"
}
string token;
};
@shafreenAnfar @daneshk we have to use the same metadata across all the stdlib.
Also note that, with Update 2, we will introduce, @constraint annotation. It describes constraints on the value, which also useful when generating UI forms.
Ok, my bad. I checked this in Ballerina 2201.0.3 (Swan Lake) and it gave me the following compilation error.
ERROR [main.bal:(44:9,44:13)] invalid key 'kind': identifiers cannot be used as rest field keys, expected a string literal or an expression
error: compilation contains errors
But no errors after updating to Ballerina 2201.1.1 (Swan Lake Update 1)
Display annotation syntax for Choreo UI elements rendering
Applied for:
- Fields in records
- Configurable variables (or generally any variable?)
Use Case 1: Masking sensitive fields
type Credentials record {
string username;
@display {
label: "auth token",
mask: true
sensitive: true
}
string token;
};
- Looking at “mask”, the UI will generate a password type text box which masks whatever typed there. If the display annotation is not there, it is considered mask=false.
- Looking at “sensitive”, the value backend logic can treat this special (i.e store in Azure key vault). If the display annotation is not there, it is considered sensitive=false.
Use Case 2: Identify file paths
type SSLConfig record {
string username;
@display {
label: "client certificate path",
kind: filePath
}
string clientCert;
};
Looking at “kind”, there will be different UI element renderings. There’s a defined set of kinds considered by Choreo UI.
Possible values for kind:
- filePath (renders file upload button next to path text box)
(Note: for now we only have filePath, however in future there may be more kinds that is supported by UI rendering logic)
@hasithaa, @abeykoon can we add these fields to the display annotation to reserve them. Otherwise people might use these for other use-cases. Also is the kind attribute an enum ?
@hevayo +1 to reserve those as optional fields.
IMO, we only need one attribute for both cases, and its values should be a subset of HTML input types.
@hevayo, Since display annotation defined in main symbol space, defining an enum for kind attribute will pollute the main symbol space. Hence I will define it something like, "text"|"date"|"password"|"time"|"file"|"url"|"tel"|"email" kind; There are other kinds we can support too.
+1 to use a union instead of enum.
Also since display annotation can be put to any constructs we should implement a validator to prevent using certain attributes in irrelevant places. ie Using mask attribute inside display annotation added to a service. But validator can come later.
We had a discussion on above proposal and decided on below
sensitiveis not used for display purpose, so should not be a part of display annotation. A future platform annotation may support it- Introduce one field like
kindwith a defined set of types. @indikasampath2000 and @abeykoon to come up with a list - Validation can come later. If we can agree to a list of words that can come for the value of
kind, it is good enough to start
As @abeykoon mentioned, we decided to have single metadata under the @display annotation to solve this problem since the @display is intended for rendering purposes. The data sensitivity has to decide by the user. The relevant tooling rendering these configuration records needs to get that information from the user for the persistent.
The kind metadata would have the following three values by looking at the existing connector configurations.
"text"|"password"|"file" kind;
The default would be "text" when there is no @display annotation for the given field.
| Connector | Configs | Kind |
|---|---|---|
| ballerinax/mysql ballerinax/mssql ballerinax/oracledb ballerinax/postgresql |
password crypto:KeyStore#path crypto:KeyStore#password crypto:TrustStore#path crypto:TrustStore#password |
password file password file password |
| ballerina/http | http:CredentialsConfig#password http:BearerTokenConfig#token http:OAuth2ClientCredentialsGrantConfig#clientSecret http:OAuth2PasswordGrantConfig#password http:OAuth2PasswordGrantConfig#clientSecret http:OAuth2RefreshTokenGrantConfig#clientSecret http:OAuth2RefreshTokenGrantConfig#refreshToken http:OAuth2JwtBearerGrantConfig#clientSecret crypto:KeyStore#path crypto:KeyStore#password crypto:TrustStore#path crypto:TrustStore#password |
password password password password password password password password file password file password |
| Ecosystem handwritten connectors | Same as ballerina/http | |
| OpenAPI generated connectors | Same as ballerina/http API Key |
Password |
@shafreenAnfar @daneshk, could you please verify the above list and add if I have missed something?
In HTML input type file means, file upload. But in our case, what we need is file-path, which is mapped to url in HTML input types.
No, here we want to give an option to upload the cert and key file. We'll generate a path after uploading the file and mount the file to the generated path at deployment.
@hasithaa @hevayo we met a scenario like this.
public type ClientSecureSocket record {|
boolean enable = true;
crypto:TrustStore|string cert?;
crypto:KeyStore|CertKey key?;
record {|
Protocol name;
string[] versions = [];
|} protocol?;
record {|
CertValidationType 'type = OCSP_STAPLING;
int cacheSize;
int cacheValidityPeriod;
|} certValidation?;
string[] ciphers?;
boolean verifyHostName = true;
boolean shareSession = true;
decimal handshakeTimeout?;
decimal sessionTimeout?;
|};
If we take crypto:TrustStore|string cert?; The UI functionality needs to be
- if selected string type, a text box will be there and content needs to be masked.
- if selected crypto:TrustStore type it should display following
public type TrustStore record {| string path; ----> Upload button string password; ----> Should be masked |};
How can we define this functionality when we have an union of a record and a basic type?
I think it is UI Form generation's decision to how to render string or record filed. What we can do is we can put @display { kind : "password" } to the cert to indicate it is a sensitive value. So when users select string, the text box will be masked. But for record filling, masking doesn't make sense and it has to get what have mentioned in thecrypto:TrustStore and use that for rendering.
@hevayo @abeykoon thoughts.