Project

General

Profile

Actions

Feature #22820

closed

Ability to create, edit and delete external credentials in workbench

Added by Peter Amstutz 11 months ago. Updated 6 months ago.

Status:
Resolved
Priority:
Normal
Assigned To:
Category:
Workbench2
Target version:
Story points:
-
Release relationship:
Auto

Description

Need a new page to work with the new credentials feature.

Requirements:

  • Display a data table listing the credentials visible to the user. It should support normal paging.
  • Have a "New credential" button
  • Have an "Edit credential" button that brings up an edit dialog (see below)
  • Have a "Share credential" button that brings up the standard sharing dialog
  • Have a "Delete credential" button

Pressing "New credential" or "Edit credential" brings up a dialog box.

The dialog box offers the following fields:

  • Name -- regular 'name' field
  • Description -- rich text editor
  • Credential id -- single line text field
  • Credential secret -- this should be a blinded password entry field, but it should permit pasting in modest-sized multi-line text blobs such as ssh private keys.
  • Credential scopes -- this is a JSON array of strings, consider using an editing control similar to how we add users for sharing where we enter text and then it is converted to a badge when the user hits return (but this is easier, we don't need autocomplete)
  • Expiration time -- provide a datetime picker (I think we have one to select the expiration time when creating anonymous sharing links to files).

"secret" is not returned by the API so it is very important, when saving edits, that "secret" is not sent to the server if it was not filled in by the user with a new value (because the empty value will wipe out the actual secret value).

Try to avoid storing secrets in redux; once the edit dialog is closed and the save/update operation has finished, the browser should forget about the secret.

  • Implement workbench2/src/services/credentials-service for the new API. It mostly follows standard resource conventions, but review the docs here: https://doc.arvados.org/main/api/methods/credentials.html
    • To figure out: Does API server advertise the list of supported credentials_class values? e.g., is it in config? If so, you can get it from there. If not, it's okay to hardcode a list of supported values (just one right now). We do not expect it to change very often so there's minimal concern about Workbench's list getting out of sync with API server's.


Files

external-credentials-UI.png (135 KB) external-credentials-UI.png Peter Amstutz, 05/08/2025 10:34 PM
xcred-expiredbadge.png (411 KB) xcred-expiredbadge.png Lisa Knox, 09/11/2025 03:47 PM
clipboard-202509121010-tc05i.png (8.42 KB) clipboard-202509121010-tc05i.png Brett Smith, 09/12/2025 02:10 PM
clipboard-202509121014-kcyog.png (3 KB) clipboard-202509121014-kcyog.png Brett Smith, 09/12/2025 02:14 PM

Subtasks 2 (0 open2 closed)

Task #22870: Interface review 22820-credentials-uiResolvedBrett Smith09/16/2025Actions
Task #22871: Branch review 22820-credentials-uiResolvedStephen Smith09/29/2025Actions

Related issues 5 (0 open5 closed)

Related to Arvados - Bug #23152: Validate schema of complex fieldsResolvedTom CleggActions
Related to Arvados - Feature #23179: Rework renderer types using GroupContentsResourceResolvedStephen SmithActions
Related to Arvados - Bug #23181: External Credentials API doesn't match the documentationResolvedLisa KnoxActions
Has duplicate Arvados - Feature #22851: New editing UI for credentialsDuplicateActions
Blocked by Arvados - Feature #22680: store persistent credentials to external resources and provide them to a containerResolvedPeter AmstutzActions
Actions #1

Updated by Peter Amstutz 11 months ago

  • Position changed from -950306 to -950301
Actions #2

Updated by Peter Amstutz 11 months ago

  • Description updated (diff)
Actions #3

Updated by Peter Amstutz 11 months ago

  • Blocked by Feature #22680: store persistent credentials to external resources and provide them to a container added
Actions #4

Updated by Peter Amstutz 11 months ago

  • Target version changed from Development 2025-05-14 to Development 2025-05-28
Actions #5

Updated by Peter Amstutz 11 months ago

  • Description updated (diff)
Actions #6

Updated by Peter Amstutz 11 months ago

Actions #7

Updated by Peter Amstutz 11 months ago

  • Subject changed from Ability to create, edit and delete credentials in workbench to Ability to create, edit and delete external credentials in workbench
Actions #8

Updated by Peter Amstutz 11 months ago

Actions #9

Updated by Peter Amstutz 11 months ago

Notes:

Setting credential_class to a known value modifies the labels for "external id" and "secret" to be more specific to the credential type.

Picking a date time for expires_at should start at the current time using the datetime picker that we use for sharing URLs. The expires_at time field should display the relative time (e.g. "in 15 days") along with a more precise date and time. It should show the relative time/precise value in the expires_at column a well.

Actions #10

Updated by Peter Amstutz 11 months ago

If you use a name that is already in use, trying to create the credential will fail. It should recognize the error message and give the use a useful error prompting them to change the name.

Actions #11

Updated by Peter Amstutz 10 months ago

  • Assigned To set to Lisa Knox
Actions #12

Updated by Peter Amstutz 10 months ago

  • Subtask #22870 added
Actions #13

Updated by Peter Amstutz 10 months ago

  • Subtask #22871 added
Actions #14

Updated by Peter Amstutz 10 months ago

  • Target version changed from Development 2025-05-28 to Development 2025-06-25
Actions #15

Updated by Peter Amstutz 10 months ago

  • Assigned To changed from Lisa Knox to Stephen Smith
Actions #16

Updated by Peter Amstutz 10 months ago

  • Release set to 79
Actions #17

Updated by Stephen Smith 9 months ago

  • Status changed from New to In Progress
Actions #18

Updated by Brett Smith 9 months ago

  • Target version changed from Development 2025-06-25 to Development 2025-07-09
Actions #19

Updated by Brett Smith 9 months ago

  • Assigned To deleted (Stephen Smith)
  • Status changed from In Progress to New
Actions #20

Updated by Brett Smith 9 months ago

  • Release deleted (79)
  • Target version deleted (Development 2025-07-09)
Actions #21

Updated by Brett Smith 8 months ago

  • Release set to 79
Actions #22

Updated by Brett Smith 8 months ago

  • Description updated (diff)
Actions #23

Updated by Brett Smith 7 months ago

  • Target version set to Development 2025-09-03
  • Assigned To set to Lisa Knox
Actions #24

Updated by Lisa Knox 7 months ago

  • Status changed from New to In Progress
Actions #25

Updated by Brett Smith 7 months ago

  • Target version changed from Development 2025-09-03 to Development 2025-09-17
Actions #26

Updated by Lisa Knox 7 months ago

  • Related to Bug #23152: Validate schema of complex fields added
Actions #27

Updated by Brett Smith 7 months ago

If a credential's scopes are not an array, the only requirement is that Workbench should not crash. You can ignore the value in rendering, overwrite it for updates, etc., all silently. The fact that the API server allows non-array values is an API server bug and you should not spend any extra development effort accommodating it.

Updated by Brett Smith 6 months ago

Setting credential_class to a known value modifies the labels for "external id" and "secret" to be more specific to the credential type.

What this means is that, e.g., once you set the credential class to aws_access_key, External ID should become AWS Access Key ID and secret should become AWS Secret Key. Lisa pointed out that this mapping would be better done in the API server discovery document/config, and I agree. We will not do this in Workbench for now, especially since there's only kind of credential class we support.

We also discussed, because there's only one credential class right now, the input can just be a plain text field with aws_access_key as the default value for new credentials. Once we support multiple classes we'll probably want an autocomplete-style text-with-pulldown input, but there's no need to implement that now.

Interface notes as of 30712e1575d751c87ff7ca9a135a9c42263ac385. I originally had more notes but I see a lot of them necessarily follow from the API design of credentials. I think you did a great job considering some of the decisions that were already made. I think would be nice improvements but aren't required and aren't worth spending a bunch of time on:

  • The "expires at" duration feels a little verbose. Especially right now, it's showing values like "in 11 months, 30 days," that should really just be "12 months." What do you think about this:
    • If the credential is expiring within 100 days, display a Failing-style red outline badge with the text "Expires in N days"
    • Otherwise, only display the date with no duration text.
  • It would be nice to have a little spacing between Search and the New button in the upper right. (I see we also have this issue on the Groups page.) Spacing like we have between Search and Column Select on project listing pages seems like it would be appropriate. Compare these two:
Actions #30

Updated by Lisa Knox 6 months ago

22820-credentials-ui @ b1eb852590e38b91a1d6b9c238e6ff815fa8c00a

developer-run-tests-services-workbench2: #1610

  • ✅ All agreed upon points are implemented / addressed.
    • New data explorer exists, with the appropriate behavior and menus in place.
    • From initial interface feedback:
      • The string "aws_access_key" now populates in the credential class field when creating a new credential.
      • A badge now appears showing the time remaining for any expiration date <100 days
      • 16 pixels now separate the search field from the "NEW EXTERNAL CREDENTIAL" button.
      • The render function for the scopes field will now adapt for any value type passed to it (i.e. If it's an array, good. If it's a string, it will be converted to an array. Other types will be ignored.).
  • ✅ Anything not implemented (discovered or discussed during work) has a follow-up story.
  • ✅ Code is tested and passing, both automated and manual, what manual testing was done is described
  • ✅ The tested code incorporates recent main branch changes.
    • Main was merged in a week ago.
  • ✅ New or changed UX/UX and has gotten feedback from stakeholders.
  • n/a Documentation has been updated.
  • ✅ Behaves appropriately at the intended scale (describe intended scale).
  • ✅ Considered backwards and forwards compatibility issues between client and server.
  • ✅ Follows our coding standards and GUI style guidelines.

Submitting both Code and interface review simultaneously because it seems likely (from previous discussion) that interface review will yield no feedback.

Actions #31

Updated by Brett Smith 6 months ago

Lisa Knox wrote in #note-30:

Submitting both Code and interface review simultaneously because it seems likely (from previous discussion) that interface review will yield no feedback.

Yup, this works for me, thank you.

I would like the "New item" button spacing change to be applied to the Groups page and any other pages that follow this same layout. I realize this is one of those awkward things where it's not really related to the issue in this ticket, but it seems so small it's kind of annoying to make its own ticket+branch+review about. How much effort is it to apply this change elsewhere? If it's easy enough, can we please just roll it into this branch? If not, please make a ticket and I'll prioritize accordingly. Thanks.

Actions #32

Updated by Lisa Knox 6 months ago

If it's easy enough, can we please just roll it into this branch?

Easily

Actions #33

Updated by Brett Smith 6 months ago

Sorry, one interface note: When editing a credential, the existing secret is not and should not be available, but it should be possible to replace the secret with a new one.

The credential edit dialog should offer a secret input like the new credential dialog, except now it's optional. It should have placeholder text "Retain current secret" (if you think there's better text I'm open to suggestions). The user may enter a new secret in this field.

When Workbench sends the POST API request to update the credential, the body MUST contain the secret field ONLY IF the user entered a new secret value. If the user left the field alone, then the update must not include a secret field so that the record retains its value on the API server.

Actions #34

Updated by Brett Smith 6 months ago

  • Target version changed from Development 2025-09-17 to Development 2025-10-01
Actions #35

Updated by Lisa Knox 6 months ago

22820-credentials-ui @ 5772592ca3e52853f0f1ab49b0a54fa52eafbbaa

developer-run-tests-services-workbench2: #1613

I would like the "New item" button spacing change to be applied to the Groups page and any other pages...

The only page I found that this applies to is the groups page, which is fixed now.

The credential edit dialog should offer a secret input...

Done, and added a unit test to ensure that when updating, the secret field is only passed if the user has changed it.

Actions #36

Updated by Stephen Smith 6 months ago

  • I noticed in the date picker, if you click on the month and press delete and the right arrow key, you can clear out the date which will reset to today, but the actual value will be null and it gives a big scary backend error toast - if it's not possible to make the actual value reset along with the displayed value when each part is deleted, it would be good to have a nicer looking error message for that (perhaps checking the value client side before sending the request)
  • In external-credentials.ts we should add kind: ResourceKind.EXTERNAL_CREDENTIAL to the type definition in line with other resource types.
    • This allows simplifying isExternalCredential to be more in line with other type guards - just checking kind instead of requiring all fields to have a truthy value. It should probably also take a Resource as a param
  • In external-credentials-actions:L62
    • The create method should probably also do a form reset() similar to the update credential method, to ensure the secret isn't lingering around in redux form.
    • Since STOP_WORKING is called in the finally blocks, it isn't needed in the try blocks
    • In loadExternalCredentials, we usually don't to logged in checks in page load functions since being logged in is checked globally, with the exception of course if we need to use auth data. I think it's better to assume the global login check passed, and if there's an edge case or permission issue, the page load should fail with an error toast anyway
  • In both create and update-external-credentials-dialog.ts, the trim on the fields doesn't actually modify the data, you could do a map/reduce to build a new object instead.
  • In string-array-input.tsx I think you can just tell TS that the input.value is a string[] by adding to the StringArrayInputProps input: { value: string[] } & WrappedFieldInputProps;, that way any casting should be unnecessary

Required field issues:

I was able to create a credential using this json (missing name, description, credential_class, and external_id):

{"expires_at":"2026-09-26T13:29:07.393Z","secret":"asd"}

Resulting in a resource like:
{
    "kind": "arvados#credential",
    "etag": "30ip83xn9ryzzv98zcak9ho9z",
    "uuid": "tordo-oss07-vno6cbf8h27q6gp",
    "owner_uuid": "tordo-tpzed-000000000000000",
    "created_at": "2025-09-26T13:30:46.912366000Z",
    "modified_by_user_uuid": "jutro-tpzed-vllbpebicy84rd5",
    "modified_at": "2025-09-26T13:30:46.912726000Z",
    "name": null,
    "description": null,
    "credential_class": null,
    "scopes": [],
    "external_id": null,
    "expires_at": "2026-09-26T13:29:07.393000000Z" 
}

Currently only the missing description seems to actually crash the UI, but for those 4 fields we should either make sure a ticket is made for the backend to actually require them or line up the type definition and handle empty/missing values.

(A side effect of having some missing fields is also that the wrong icon is shown, but changing isExternalCredential as above should fix that)

I also created #23179 to do some of the tangentially related type adjustments that I noticed should be done

Actions #37

Updated by Stephen Smith 6 months ago

  • Related to Feature #23179: Rework renderer types using GroupContentsResource added
Actions #38

Updated by Brett Smith 6 months ago

Stephen Smith wrote in #note-36:

I was able to create a credential using this json (missing name, description, credential_class, and external_id):

The Workbench implementation follows what the API documentation says is required, so, the documentation is buggy too. My preference is:

  • We make a ticket for API server to require most of these fields and update the documentation to match.
  • But I would prefer we didn't require description, so if we're revisiting this anyway I would prefer if Workbench didn't require it and could handle it being unset.
Actions #39

Updated by Stephen Smith 6 months ago

Sounds good, so on the WB side we just need to make the description type optional and make it not crash.

Actions #40

Updated by Lisa Knox 6 months ago

  • Related to Bug #23181: External Credentials API doesn't match the documentation added
Actions #41

Updated by Lisa Knox 6 months ago

22820-credentials-ui @ 2482a59842212f6097031a48a84e95f3ae4f256f

developer-run-tests-services-workbench2: #1616

  • I noticed in the date picker, if you click on the month and press delete...

Fixed. The date picker will now error if the date is in any way invalid, causing a red border and the submit button to be disabled.

  • In external-credentials.ts we should add kind: ResourceKind.EXTERNAL_CREDENTIAL...
  • In external-credentials-actions:L62
    • The create method should probably also do a form reset()...
    • Since STOP_WORKING is called in the finally blocks, it isn't needed in the try blocks
    • In loadExternalCredentials, we usually don't to logged in checks...

Done

  • In both create and update-external-credentials-dialog.ts, the trim on the fields doesn't actually modify the data, you could do a map/reduce to build a new object instead.

Replaced with a for loop

  • In string-array-input.tsx I think you can just tell TS that the input.value is a string[]...

Done, this was a source of frustration, thanks

Required field issues:

#23181

The only optional fields are now "description" and "scopes". Workbench renderers for the External Credentials panel have been modified to handle cases where the API returns null for their fields.

Actions #42

Updated by Stephen Smith 6 months ago

  • The date picker seems to still allow you to try to create a credential with no date - if you press the delete key after selecting Y/M/D it still clears the date (though it visually resets to the initial value) and gives a big error toast when submitted.
  • There's 1 remaining as string[] in string-array-mui-input.tsx
Actions #43

Updated by Lisa Knox 6 months ago

developer-run-tests-services-workbench2: #1623 /console

  • The date picker seems to still allow you to try to create a credential with no date...

Fixed. Now any time the date picker is cleared, the value is set to the default date and the onchange is called so that it will be passed to redux-form.

  • There's 1 remaining as string[] in string-array-mui-input.tsx

Removed

Actions #44

Updated by Stephen Smith 6 months ago

Just 1 thing, it seems like isValidDate requires a date in the future if I'm reading it right - it might be clearer to call it isValidFutureDate or something to make that more clear.

Besides that lgtm!

Actions #45

Updated by Lisa Knox 6 months ago

  • Status changed from In Progress to Resolved
Actions

Also available in: Atom PDF