Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global vulnerability audit view broken for MSSQL #3692

Closed
2 tasks done
schnieders opened this issue May 10, 2024 · 15 comments · Fixed by #3700
Closed
2 tasks done

Global vulnerability audit view broken for MSSQL #3692

schnieders opened this issue May 10, 2024 · 15 comments · Fixed by #3700
Labels
defect Something isn't working p1 Critical bugs that prevent DT from being used, or features that must be implemented ASAP size/M Medium effort
Milestone

Comments

@schnieders
Copy link

Current Behavior

After updating to 4.11, the new global audit view (see #2472) shows no vulnerabilities on the "Vulnerabilities By Occurrence" tab due to a server side database exception. Vulnerabilities on the tab "Grouped Vulnerabilities" are shown correctly.

2024-05-10 08:23:10,414 ERROR [GlobalExceptionHandler] Uncaught internal server error
javax.jdo.JDODataStoreException: Error executing SQL query "SELECT DISTINCT        "COMPONENT"."UUID"      , "COMPONENT"."NAME"      , "COMPONENT"."GROUP"      , "COMPONENT"."VERSION"      , "COMPONENT"."PURL"      , "COMPONENT"."CPE"      , "VULNERABILITY"."UUID"      , "VULNERABILITY"."SOURCE"      , "VULNERABILITY"."VULNID"      , "VULNERABILITY"."TITLE"      , "VULNERABILITY"."SUBTITLE"      , "VULNERABILITY"."DESCRIPTION"      , "VULNERABILITY"."RECOMMENDATION"      , "VULNERABILITY"."SEVERITY"      , "VULNERABILITY"."CVSSV2BASESCORE"      , "VULNERABILITY"."CVSSV3BASESCORE"      , "VULNERABILITY"."OWASPRRLIKELIHOODSCORE"      , "VULNERABILITY"."OWASPRRTECHNICALIMPACTSCORE"      , "VULNERABILITY"."OWASPRRBUSINESSIMPACTSCORE"      , "VULNERABILITY"."EPSSSCORE"      , "VULNERABILITY"."EPSSPERCENTILE"      , "VULNERABILITY"."CWES"      , "FINDINGATTRIBUTION"."ANALYZERIDENTITY"      , "FINDINGATTRIBUTION"."ATTRIBUTED_ON"      , "FINDINGATTRIBUTION"."ALT_ID"      , "FINDINGATTRIBUTION"."REFERENCE_URL"      , "ANALYSIS"."STATE"      , "ANALYSIS"."SUPPRESSED"      , "VULNERABILITY"."PUBLISHED"      , "PROJECT"."UUID"      , "PROJECT"."NAME"      , "PROJECT"."VERSION"   FROM "COMPONENT"  INNER JOIN "COMPONENTS_VULNERABILITIES"     ON "COMPONENT"."ID" = "COMPONENTS_VULNERABILITIES"."COMPONENT_ID"  INNER JOIN "VULNERABILITY"     ON "COMPONENTS_VULNERABILITIES"."VULNERABILITY_ID" = "VULNERABILITY"."ID"  INNER JOIN "FINDINGATTRIBUTION"     ON "COMPONENT"."ID" = "FINDINGATTRIBUTION"."COMPONENT_ID"    AND "VULNERABILITY"."ID" = "FINDINGATTRIBUTION"."VULNERABILITY_ID"   LEFT JOIN "ANALYSIS"     ON "COMPONENT"."ID" = "ANALYSIS"."COMPONENT_ID"    AND "VULNERABILITY"."ID" = "ANALYSIS"."VULNERABILITY_ID"    AND "COMPONENT"."PROJECT_ID" = "ANALYSIS"."PROJECT_ID"  INNER JOIN "PROJECT"     ON "COMPONENT"."PROJECT_ID" = "PROJECT"."ID"   LEFT JOIN "PROJECT_ACCESS_TEAMS"     ON "PROJECT"."ID" = "PROJECT_ACCESS_TEAMS"."PROJECT_ID"  WHERE ("ANALYSIS"."SUPPRESSED" = ? OR "ANALYSIS"."SUPPRESSED" IS NULL) ORDER BY "FINDINGATTRIBUTION"."ATTRIBUTED_ON"  DESC".
	at org.datanucleus.api.jdo.JDOAdapter.getJDOExceptionForNucleusException(JDOAdapter.java:605)
	at org.datanucleus.api.jdo.JDOQuery.executeInternal(JDOQuery.java:456)
	at org.datanucleus.api.jdo.JDOQuery.executeList(JDOQuery.java:345)
	at org.dependencytrack.persistence.FindingsSearchQueryManager.getAllFindings(FindingsSearchQueryManager.java:127)
	at org.dependencytrack.persistence.QueryManager.getAllFindings(QueryManager.java:1087)
	at org.dependencytrack.resources.v1.FindingResource.getAllFindings(FindingResource.java:270)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:146)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:189)
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:176)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:93)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:478)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:400)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:81)
	at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:256)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:235)
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:684)
	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:394)
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:358)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:311)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)
	at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1419)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:764)
	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1665)
	at alpine.server.filters.ContentSecurityPolicyFilter.doFilter(ContentSecurityPolicyFilter.java:225)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1635)
	at alpine.server.filters.ClickjackingFilter.doFilter(ClickjackingFilter.java:93)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1635)
	at alpine.server.filters.WhitelistUrlFilter.doFilter(WhitelistUrlFilter.java:166)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:210)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1635)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:527)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:131)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:598)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:223)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1570)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1384)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:484)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1543)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1306)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.server.Server.handle(Server.java:563)
	at org.eclipse.jetty.server.HttpChannel$RequestDispatchable.dispatch(HttpChannel.java:1598)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:753)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:501)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:287)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:314)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:421)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:390)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:277)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:199)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:411)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
	at java.base/java.lang.Thread.run(Unknown Source)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The text data type cannot be selected as distinct because it is not comparable.
	at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:261)
	at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1752)
	at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:675)
	at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:594)
	at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7739)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:4384)
	at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:293)
	at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:263)
	at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:509)
	at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
	at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
	at org.datanucleus.store.rdbms.SQLController.executeStatementQuery(SQLController.java:584)
	at org.datanucleus.store.rdbms.query.SQLQuery.performExecute(SQLQuery.java:669)
	at org.datanucleus.store.query.Query.executeQuery(Query.java:2004)
	at org.datanucleus.store.rdbms.query.SQLQuery.executeWithMap(SQLQuery.java:840)
	at org.datanucleus.api.jdo.JDOQuery.executeInternal(JDOQuery.java:437)
	... 72 common frames omitted

Steps to Reproduce

  1. Update an existing instance with data from 4.10 to 4.11 using MSSQL
  2. Access the "Vulnerability Audit" section with the "Vulnerabilities By Occurrence" tab and do not apply any filter.

Expected Behavior

There is no database exception and the vulnerabilities on the tab "Vulnerabilities By Occurrence" are shown correctly

Dependency-Track Version

4.11.0

Dependency-Track Distribution

Container Image

Database Server

Microsoft SQL Server

Database Server Version

15.0.4365.2

Browser

Google Chrome

Checklist

@schnieders schnieders added defect Something isn't working in triage labels May 10, 2024
@rkg-mm
Copy link
Contributor

rkg-mm commented May 10, 2024

Seems like DTrack uses TEXT datatype, but MSSQL doesn't support DISTINCT on it.
According to https://stackoverflow.com/questions/8056339/ef-the-text-data-type-cannot-be-selected-as-distinct-because-it-is-not-comparab
the question should be: Why do we use TEXT as datatype instead VARCHAR(MAX)?

@nscuro
Copy link
Member

nscuro commented May 10, 2024

@rkg-mm Limitation of the ORM we use. It maps the CLOB JDBC type (required for "string of unlimited size") to TEXT for SQL Server: https://github.com/datanucleus/datanucleus-rdbms/blob/ae929d4a97961ebc53a21a4d0bf4c845ebdf4705/src/main/java/org/datanucleus/store/rdbms/adapter/SQLServerAdapter.java#L173-L175

It's not a decision we actively made to choose TEXT over VARCHAR(MAX)...

@rkg-mm
Copy link
Contributor

rkg-mm commented May 10, 2024

Which fields would be affected by this? Since you drop support for MSSQL anyway with 5.x, maybe as quick fix those fields can be excluded...

@nscuro
Copy link
Member

nscuro commented May 10, 2024

Based on the query in the exception, it seems to be these:

@Persistent
@Column(name = "DESCRIPTION", jdbcType = "CLOB")
@JsonDeserialize(using = TrimmedStringDeserializer.class)
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS_PLUS, message = "The description may only contain printable characters")
private String description;

@Persistent
@Column(name = "RECOMMENDATION", jdbcType = "CLOB")
@JsonDeserialize(using = TrimmedStringDeserializer.class)
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS_PLUS, message = "The recommendation may only contain printable characters")
private String recommendation;

@rkg-mm
Copy link
Contributor

rkg-mm commented May 10, 2024

For the moment those are not used in the UI, but could be in future once we add expanding of those table rows.

Could also cast these 2 in the query
CAST(field AS VARCHAR(MAX))
Just not sure how that impacts performance of the query.

@nscuro
Copy link
Member

nscuro commented May 10, 2024

I'm wondering if we need DISTINCT at all here. The query doesn't look like it would produce duplicate rows, as it operates on the concept of findings (Component <-> Vulnerability pairs). Am I missing something?

CAST(field AS VARCHAR(MAX))

I'd expect this to slow down the query, but not sure by how much. Also this would need to be a specific cast for SQL Server, since the same will not work in H2, MySQL, or PostgreSQL.

@rbt-mm
Copy link
Contributor

rbt-mm commented May 10, 2024

I'm wondering if we need DISTINCT at all here. The query doesn't look like it would produce duplicate rows, as it operates on the concept of findings (Component <-> Vulnerability pairs). Am I missing something?

AFAIK DISTINCT was necessary because the query could otherwise produce duplicate rows if ACL is enabled.
Without it if a user is a part of multiple teams and two of those different teams include the same project, the query would produce a duplicate entry for both project teams.

Maybe there's a fix to this problem that does not include DISTINCT in the query, but unfortunately I'm not the biggest SQL expert 😅.

@nscuro
Copy link
Member

nscuro commented May 10, 2024

Perhaps there is a way to solve this in a "two-stage" CTE, where we:

  1. Select only the unique IDs of all applicable findings (this can use DISTINCT)
  2. Based on the CTE holding the IDs, fetch the actual fields we want to display (doesn't need DISTINCT anymore)

Separately, are you seeing the same issue in your instance @rbt-mm @rkg-mm?

I'm 99% sure I tested this feature with the MSSQL Compose setup, so I am a bit baffled why it may have worked before but then somehow broke. Does the MSSQL version play a role? The Compose setup uses the 2022 version.

@rkg-mm
Copy link
Contributor

rkg-mm commented May 10, 2024

I haven't found the time to update our instance yet. But I also think @rbt-mm tested this with MSSQL...

@rbt-mm
Copy link
Contributor

rbt-mm commented May 10, 2024

I currently don't have MSSQL installed so I can't try to reproduce the issue but I'm 100% sure that I successfully tested this with MSSQL 2022 when I created the PR.

@nscuro
Copy link
Member

nscuro commented May 10, 2024

I'll try to reproduce later today.

@schnieders
Copy link
Author

schnieders commented May 10, 2024

Thank you for your immediate reactions. I would like to share some additional logs with you, which shows the database migration done by DT API server. Maybe it will help you.

2024-05-08 08:18:45,250 INFO [RequirementsVerifier] Initializing requirements verifier
2024-05-08 08:18:45,251 INFO [UpgradeInitializer] Initializing upgrade framework
2024-05-08 08:18:48,009 INFO [UpgradeExecutor] Upgrade class org.dependencytrack.upgrade.v4110.v4110Updater about to run.
2024-05-08 08:18:48,009 INFO [v4110Updater] Dropping foreign key constraint from "VULNERABILITY"."CWE"
2024-05-08 08:18:48,011 INFO [v4110Updater] Dropping index "VULNERABILITY"."VULNERABILITY_CWE_IDX"
2024-05-08 08:18:48,011 INFO [v4110Updater] Dropping column "VULNERABILITY"."CWE"
2024-05-08 08:18:48,013 INFO [v4110Updater] Dropping table "CWE"
2024-05-08 08:18:48,020 INFO [v4110Updater] Computing severities for vulnerabilities where severity is currently NULL
2024-05-08 08:18:48,778 INFO [v4110Updater] Updated 12753 vulnerabilities in 26 batches
2024-05-08 08:18:48,780 INFO [v4110Updater] Extending length of PURL and PURLCOORDINATES columns from 255 to 786
2024-05-08 08:18:48,806 INFO [UpgradeExecutor] Completed running upgrade class org.dependencytrack.upgrade.v4110.v4110Updater in 778 ms.
2024-05-08 08:18:48,809 INFO [PersistenceManagerFactory] Initializing persistence framework
2024-05-08 08:18:48,810 INFO [PersistenceManagerFactory] Creating transactional connection pool
2024-05-08 08:18:48,844 INFO [PersistenceManagerFactory] Creating non-transactional connection pool
2024-05-08 08:18:49,844 INFO [HealthCheckInitializer] Registering health checks
2024-05-08 08:18:49,846 INFO [DefaultObjectGenerator] Initializing default object generator
2024-05-08 08:18:49,847 INFO [DefaultObjectGenerator] Synchronizing permissions to datastore
2024-05-08 08:18:50,036 INFO [DefaultObjectGenerator] Synchronizing SPDX license definitions to datastore
2024-05-08 08:18:57,408 INFO [DefaultObjectGenerator] Synchronizing default repositories to datastore
2024-05-08 08:18:57,462 INFO [DefaultObjectGenerator] Synchronizing config properties to datastore
2024-05-08 08:18:57,685 INFO [DefaultObjectGenerator] Synchronizing notification publishers to datastore
2024-05-08 08:18:58,115 INFO [EventSubsystemInitializer] Initializing asynchronous event subsystem
2024-05-08 08:18:58,152 INFO [NotificationSubsystemInitializer] Initializing notification service
2024-05-08 08:18:58,154 INFO [IndexSubsystemInitializer] Building lucene indexes if required
2024-05-08 08:18:58,165 INFO [IndexManager] Checking the health of index PROJECT
2024-05-08 08:18:58,331 INFO [IndexManager] The index PROJECT is healthy
2024-05-08 08:18:58,332 INFO [IndexManager] Checking the health of index COMPONENT
2024-05-08 08:18:58,917 INFO [IndexManager] The index COMPONENT is healthy
2024-05-08 08:18:58,918 INFO [IndexManager] Checking the health of index SERVICECOMPONENT
2024-05-08 08:18:58,919 INFO [IndexManager] The index SERVICECOMPONENT is healthy
2024-05-08 08:18:58,919 INFO [IndexManager] Checking the health of index VULNERABILITY
2024-05-08 08:19:04,172 INFO [IndexManager] The index VULNERABILITY is healthy
2024-05-08 08:19:04,173 INFO [IndexManager] Checking the health of index LICENSE
2024-05-08 08:19:04,179 INFO [IndexManager] The index LICENSE is healthy
2024-05-08 08:19:04,179 INFO [IndexManager] Checking the health of index VULNERABLESOFTWARE
2024-05-08 08:19:05,575 INFO [IndexManager] The index VULNERABLESOFTWARE is healthy
2024-05-08 08:19:05,590 INFO [AlpineServlet] Starting Dependency-Track
2024-05-08 08:19:07,914 INFO [AlpineServlet] Dependency-Track is ready

There are no error messages beside this issue.

@nscuro nscuro added p1 Critical bugs that prevent DT from being used, or features that must be implemented ASAP size/M Medium effort and removed in triage labels May 13, 2024
@nscuro
Copy link
Member

nscuro commented May 13, 2024

Confirmed to be broken for MSSQL.

@nscuro nscuro changed the title Global vulnerability audit view shows empty table Global vulnerability audit view broken for MSSQL May 13, 2024
nscuro added a commit to nscuro/dependency-track that referenced this issue May 13, 2024
MSSQL does not support `DISTINCT` for columns of type `TEXT`, which `DESCRIPTION` and `RECOMMENDATION` are.

Because the database schema is controlled by DataNucleus, and DataNucleus doesn't allow us to customize column types for specific RDBMSes, changing the respective columns to `VARCHAR(MAX)` is not possible.

`DISTINCT` was needed because finding rows are joined with the `PROJECT_ACCESS_TEAMS` table, to support portfolio ACLs. If a user is member of multiple teams, the query would yield a duplicate row for each permitted team the user is a member of.

The need for `DISTINCT` is eliminated by converting the ACL check from a `LEFT JOIN` to an `EXISTS` subquery.

Fixes DependencyTrack#3692

Signed-off-by: nscuro <nscuro@protonmail.com>
@nscuro
Copy link
Member

nscuro commented May 13, 2024

Working around this now by using a subquery instead of a LEFT JOIN to perform the ACL check: #3700.

nscuro added a commit to nscuro/dependency-track that referenced this issue May 13, 2024
MSSQL does not support `DISTINCT` for columns of type `TEXT`, which `DESCRIPTION` and `RECOMMENDATION` are.

Because the database schema is controlled by DataNucleus, and DataNucleus doesn't allow us to customize column types for specific RDBMSes, changing the respective columns to `VARCHAR(MAX)` is not possible.

`DISTINCT` was needed because finding rows are joined with the `PROJECT_ACCESS_TEAMS` table, to support portfolio ACLs. If a user is member of multiple teams, the query would yield a duplicate row for each permitted team the user is a member of.

The need for `DISTINCT` is eliminated by converting the ACL check from a `LEFT JOIN` to an `EXISTS` subquery.

Fixes DependencyTrack#3692

Signed-off-by: nscuro <nscuro@protonmail.com>
@nscuro nscuro modified the milestones: 4.12, 4.11.1 May 14, 2024
Copy link
Contributor

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 15, 2024
MM-msr pushed a commit to MM-msr/dependency-track that referenced this issue Jun 18, 2024
MSSQL does not support `DISTINCT` for columns of type `TEXT`, which `DESCRIPTION` and `RECOMMENDATION` are.

Because the database schema is controlled by DataNucleus, and DataNucleus doesn't allow us to customize column types for specific RDBMSes, changing the respective columns to `VARCHAR(MAX)` is not possible.

`DISTINCT` was needed because finding rows are joined with the `PROJECT_ACCESS_TEAMS` table, to support portfolio ACLs. If a user is member of multiple teams, the query would yield a duplicate row for each permitted team the user is a member of.

The need for `DISTINCT` is eliminated by converting the ACL check from a `LEFT JOIN` to an `EXISTS` subquery.

Fixes DependencyTrack#3692

Signed-off-by: nscuro <nscuro@protonmail.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
defect Something isn't working p1 Critical bugs that prevent DT from being used, or features that must be implemented ASAP size/M Medium effort
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants