Repository navigation
✨ QD-13415 Exchange organization API token for a project token - #1052
Theodor Port (taport) wants to merge 3 commits into
Conversation
Users can supply QODANA_ORG_TOKEN plus a project slug (team-slug:project-slug) from QODANA_PROJECT_SLUG or 'projectSlug:' in qodana.yaml instead of QODANA_TOKEN. At startup the CLI exchanges them via the Qodana Public API (POST /public/organizations/projects) for a project token valid for 6 hours. - the linter/container only ever sees the project token via QODANA_TOKEN - QODANA_ORG_TOKEN is removed from the process env, container env and debug output - the exchanged token is never saved to the keyring - each slug part must be 3-64 chars of letters, digits, space, '-', '.', '_' Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fb0074a386
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "Codex (@codex) review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".
Qodana for Go139 new problems were found
@@ Code coverage @@
+ 64% total lines covered
11680 lines analyzed, 7546 lines covered
# Calculated according to the filters of your coverage tool☁️ View the detailed Qodana report Contact Qodana teamContact us at qodana-support@jetbrains.com
|
- rename OrgTokenDeclinedError to ErrOrgTokenDeclined (ST1012) - don't end the declined error format string with punctuation (ST1005) - drop QODANA_ORG_TOKEN from --env options after resolution so it never reaches the scan context and its debug output - move env filtering helpers to qdenv Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
This pull request has been automatically marked as stale because it has not had recent activity for 7 days. What happens next?
Thank you for your contribution! 🙏 |
Qodana for Go134 new problems were found
@@ Code coverage @@
+ 66% total lines covered
11671 lines analyzed, 7775 lines covered
# Calculated according to the filters of your coverage tool☁️ View the detailed Qodana report Contact Qodana teamContact us at qodana-support@jetbrains.com
|
|
This pull request has been automatically closed due to inactivity. Don't worry! You can always:
Thank you for your contribution! 🙏 |
| Ide string `yaml:"ide,omitempty"` | ||
|
|
||
| // ProjectSlug identifies the Qodana Cloud project (team-slug:project-slug) for QODANA_ORG_TOKEN exchange. | ||
| ProjectSlug string `yaml:"projectSlug,omitempty"` |
There was a problem hiding this comment.
this change should be committed after we add support for new property in linters -> unknown properties in qodana.yaml result in QodanaException. Otherwise linter will throw unknown property exceptions
| // InitializeQodanaGlobalEnv initializes the global env and resolves QODANA_ORG_TOKEN into QODANA_TOKEN if it is set. | ||
| func InitializeQodanaGlobalEnv(provider qdenv.EnvProvider, projectDir string, configName string) { | ||
| qdenv.InitializeQodanaGlobalEnv(provider) | ||
| ResolveOrgToken(projectDir, configName) |
There was a problem hiding this comment.
Let's assume that QODANA_ORG_TOKEN is set globally.
We're generating token and doing calls for every qodana command. I don't think we need to do this at least for init and pull as these are purely local. show can also be executed on localhost report.
For example when customer tries to show localhost report and there is no connection to cloud - it will not allow it to do so.
I think we should run the call only when it is really needed (like scan or send)
| if err != nil { | ||
| var apiErr *APIError | ||
| if errors.As(err, &apiErr) && slices.Contains(request.AcceptedStatuses, apiErr.StatusCode) { | ||
| return "", fmt.Errorf("%w: %v", ErrOrgTokenDeclined, err) |
There was a problem hiding this comment.
this will return ErrOrgTokenDeclined also for 401 and 404 what can be very misleading and hide actual cloud problems.
| cmdBuilder.WriteString(fmt.Sprintf("-u %s ", cfg.Config.User)) | ||
| } | ||
| for _, env := range cfg.Config.Env { | ||
| if qdenv.IsEnv(env, qdenv.QodanaOrgToken) { |
There was a problem hiding this comment.
I think we already removed it at line 312
|
|
||
| // ResolveOrgToken exchanges QODANA_ORG_TOKEN for a project token and stores it as QODANA_TOKEN in the global env. | ||
| // Does nothing if QODANA_ORG_TOKEN is not set. Must be called right after qdenv.InitializeQodanaGlobalEnv. | ||
| func ResolveOrgToken(projectDir string, configName string) { |
There was a problem hiding this comment.
this func can be inlined
|
|
||
| // setLocalUploadToken passes the resolved upload token to the locally launched linter, which inherits the CLI env. | ||
| // The token may come from the keyring or QODANA_ORG_TOKEN exchange, not only from QODANA_TOKEN env. | ||
| func setLocalUploadToken(c corescan.Context) { |
There was a problem hiding this comment.
please check if we can reuse startup.prepareQodanaTokenForNative - looks similar
|
|
||
| // tokenFromExchange is true when QODANA_TOKEN was obtained by exchanging QODANA_ORG_TOKEN. | ||
| // Such a token is short-lived, so it is never saved to the keyring. | ||
| var tokenFromExchange = false |
There was a problem hiding this comment.
I'm wondering if need to do it via global param. Isn't simple check if QODANA_ORG_TOKEN != null enough? If we have QODANA_TOKEN and QODANA_ORG_TOKEN - it looks like QODANA_TOKEN needed to be set from ORG_TOKEN. Otherwise we will fail at checks before.
| result, err := c.client.doRequest(&request) | ||
| if err != nil { | ||
| var apiErr *APIError | ||
| if errors.As(err, &apiErr) && slices.Contains(request.AcceptedStatuses, apiErr.StatusCode) { |
There was a problem hiding this comment.
electronic friend suggested that && slices.Contains(request.AcceptedStatuses, apiErr.StatusCode) is unnecessary here as it always resolves to true and we can just leave simple if errors.As(err, &apiErr)
There was a problem hiding this comment.
We agreed to use QODANA_PROJECT and qodana.yaml:project instead of slugs
| } | ||
|
|
||
| // InitializeQodanaGlobalEnv initializes the global env and resolves QODANA_ORG_TOKEN into QODANA_TOKEN if it is set. | ||
| func InitializeQodanaGlobalEnv(provider qdenv.EnvProvider, projectDir string, configName string) { |
There was a problem hiding this comment.
now qdenv and tokenloader has the same func name and one calls another - I suggest we inline qdenv function here as it is the only usage and make one function to initialize Qodana's global envs.
UNLESS we will cut tokenloading from some commands like init and pull then this will precisely show us which commands go with which path.
Users can supply QODANA_ORG_TOKEN plus a project slug (team-slug:project-slug) from QODANA_PROJECT_SLUG or 'projectSlug:' in qodana.yaml instead of QODANA_TOKEN. At startup the CLI exchanges them via the Qodana Public API (POST /public/organizations/projects) for a project token valid for 6 hours.
Checklist