Skip to content

✨ QD-13415 Exchange organization API token for a project token - #1052

Open
Theodor Port (taport) wants to merge 3 commits into
mainfrom
port/QD-13415-exchange-org-api-token
Open

Theodor Port (taport) wants to merge 3 commits into
mainfrom
port/QD-13415-exchange-org-api-token

Conversation

@taport

Copy link
Copy Markdown
Contributor

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, '-', '.', '_'

Checklist

  • I have read the CONTRIBUTING document.
  • My code follows the code style of this project.
  • My commit messages are styled with gitmoji
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

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>
@taport
Theodor Port (taport) requested a review from a team as a code owner September 23, 2026 14:41
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-23T14:46:40.177333Z fb0074a PR opened
ℹ️ About Codex in GitHub

Your 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread internal/cmd/scan.go
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Qodana for Go

139 new problems were found

Inspection name Severity Problems
Check dependency licenses 🔴 Failure 5
Vulnerable declared dependency 🔴 Failure 1
Check GO source code coverage 🔶 Warning 74
Unhandled error 🔶 Warning 13
Potential resource leak 🔶 Warning 6
Check dependency licenses 🔶 Warning 4
Deprecated element 🔶 Warning 4
Imported package name as a name identifier 🔶 Warning 3
Reserved word used as name 🔶 Warning 1
Vulnerable declared dependency 🔶 Warning 1
Unsorted imports ◽️ Notice 13
Name starts with a package name ◽️ Notice 8
Empty slice declared using a literal ◽️ Notice 3
Comment of exported element starts with the incorrect name ◽️ Notice 1
Redundant type conversion ◽️ Notice 1
Vulnerable declared dependency ◽️ Notice 1
@@ 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 team

Contact 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>
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had recent activity for 7 days.

What happens next?

  • If this PR is still relevant, please add a comment or push new commits to keep it active
  • If no activity occurs within 3 days, this PR will be automatically closed
  • You can always reopen the PR later if needed
  • You can also add a label 'wip' to keep the PR open

Thank you for your contribution! 🙏

@github-actions github-actions Bot added the stale label Oct 1, 2026
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Qodana for Go

134 new problems were found

Inspection name Severity Problems
Check dependency licenses 🔴 Failure 5
Vulnerable declared dependency 🔴 Failure 3
Check GO source code coverage 🔶 Warning 67
Unhandled error 🔶 Warning 13
Potential resource leak 🔶 Warning 6
Check dependency licenses 🔶 Warning 4
Deprecated element 🔶 Warning 4
Imported package name as a name identifier 🔶 Warning 3
Vulnerable declared dependency 🔶 Warning 3
Reserved word used as name 🔶 Warning 1
Unsorted imports ◽️ Notice 9
Name starts with a package name ◽️ Notice 8
Empty slice declared using a literal ◽️ Notice 3
Vulnerable declared dependency ◽️ Notice 3
Comment of exported element starts with the incorrect name ◽️ Notice 1
Redundant type conversion ◽️ Notice 1
@@ 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 team

Contact us at qodana-support@jetbrains.com

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

This pull request has been automatically closed due to inactivity.

Don't worry! You can always:

  • Reopen this PR if you want to continue working on it
  • Create a new PR with your changes
  • Reach out to the maintainers if you need help

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"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this func can be inlined

Comment thread internal/core/ide.go

// 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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants