Skip to content

Commit

Permalink
Integrated code lifecycle: Improve access log handling (#9425)
Browse files Browse the repository at this point in the history
(cherry picked from commit fc00f56)
  • Loading branch information
SimonEntholzer committed Oct 21, 2024
1 parent 16f33a5 commit 74f70a8
Show file tree
Hide file tree
Showing 21 changed files with 392 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ public enum AuthenticationMechanism {
* The user used the artemis client code editor to authenticate to the LocalVC
*/
CODE_EDITOR,
/**
* The user attempted to authenticate to the LocalVC using either a user token or a participation token
*/
VCS_ACCESS_TOKEN,
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ public void setCommitHash(String commitHash) {
this.commitHash = commitHash;
}

public void setRepositoryActionType(RepositoryActionType repositoryActionType) {
this.repositoryActionType = repositoryActionType;
}

public User getUser() {
return user;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ default ProgrammingExerciseStudentParticipation findByExerciseIdAndStudentLoginO
return getValueElseThrow(findByExerciseIdAndStudentLogin(exerciseId, username));
}

Optional<ProgrammingExerciseStudentParticipation> findByRepositoryUri(String repositoryUri);

default ProgrammingExerciseStudentParticipation findByRepositoryUriElseThrow(String repositoryUri) {
return getValueElseThrow(findByRepositoryUri(repositoryUri));
}

@EntityGraph(type = LOAD, attributePaths = { "submissions" })
Optional<ProgrammingExerciseStudentParticipation> findWithSubmissionsByExerciseIdAndStudentLogin(long exerciseId, String username);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ public interface SolutionProgrammingExerciseParticipationRepository
""")
Optional<SolutionProgrammingExerciseParticipation> findByBuildPlanIdWithResults(@Param("buildPlanId") String buildPlanId);

Optional<SolutionProgrammingExerciseParticipation> findByRepositoryUri(String repositoryUri);

default SolutionProgrammingExerciseParticipation findByRepositoryUriElseThrow(String repositoryUri) {
return getValueElseThrow(findByRepositoryUri(repositoryUri));
}

@EntityGraph(type = LOAD, attributePaths = { "results", "submissions", "submissions.results" })
Optional<SolutionProgrammingExerciseParticipation> findWithEagerResultsAndSubmissionsByProgrammingExerciseId(long exerciseId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ default TemplateProgrammingExerciseParticipation findWithEagerResultsAndSubmissi
return getValueElseThrow(findWithEagerResultsAndSubmissionsByProgrammingExerciseId(exerciseId));
}

Optional<TemplateProgrammingExerciseParticipation> findByRepositoryUri(String repositoryUri);

default TemplateProgrammingExerciseParticipation findByRepositoryUriElseThrow(String repositoryUri) {
return getValueElseThrow(findByRepositoryUri(repositoryUri));
}

@EntityGraph(type = LOAD, attributePaths = { "results", "results.feedbacks", "results.feedbacks.testCase", "submissions" })
Optional<TemplateProgrammingExerciseParticipation> findWithEagerResultsAndFeedbacksAndTestCasesAndSubmissionsByProgrammingExerciseId(long exerciseId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ public interface VcsAccessLogRepository extends ArtemisJpaRepository<VcsAccessLo
* @return a log entry belonging to the participationId, which has no commit hash
*/
@Query("""
SELECT vcsAccessLog
FROM VcsAccessLog vcsAccessLog
WHERE vcsAccessLog.participation.id = :participationId
AND vcsAccessLog.commitHash IS NULL
ORDER BY vcsAccessLog.timestamp DESC
LIMIT 1
""")
Optional<VcsAccessLog> findNewestByParticipationIdWhereCommitHashIsNull(@Param("participationId") long participationId);
FROM VcsAccessLog vcsAccessLog
WHERE vcsAccessLog.participation.id = :participationId
ORDER BY vcsAccessLog.timestamp DESC
LIMIT 1
""")
Optional<VcsAccessLog> findNewestByParticipationId(@Param("participationId") long participationId);

/**
* Retrieves a list of {@link VcsAccessLog} entities associated with the specified participation ID.
Expand All @@ -62,7 +62,6 @@ public interface VcsAccessLogRepository extends ArtemisJpaRepository<VcsAccessLo
* The results are ordered by the log ID in ascending order.
*
* @param date The date before which all log ids should be fetched
*
* @return a list of ids of the access logs, which have a timestamp before the date
*/
@Query("""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ public void resetRepository(VcsRepositoryUri targetURL, VcsRepositoryUri sourceU
* @return the participation.
* @throws EntityNotFoundException if the participation could not be found.
*/
public ProgrammingExerciseParticipation getParticipationForRepository(ProgrammingExercise exercise, String repositoryTypeOrUserName, boolean isPracticeRepository,
public ProgrammingExerciseParticipation retrieveParticipationForRepository(ProgrammingExercise exercise, String repositoryTypeOrUserName, boolean isPracticeRepository,
boolean withSubmissions) {

boolean isAuxiliaryRepository = auxiliaryRepositoryService.isAuxiliaryRepositoryOfExercise(repositoryTypeOrUserName, exercise);
Expand Down Expand Up @@ -502,6 +502,27 @@ public ProgrammingExerciseParticipation getParticipationForRepository(Programmin
return findStudentParticipationByExerciseAndStudentLoginAndTestRunOrThrow(exercise, repositoryTypeOrUserName, isPracticeRepository, withSubmissions);
}

/**
* Get the participation for a given repository url and a repository type or user name. This method is used by the local VC system to get the
* participation for logging operations on the repository.
*
* @param repositoryTypeOrUserName the name of the user or the type of the repository
* @param repositoryURI the participation's repository URL
* @return the participation belonging to the provided repositoryURI and repository type or username
*/
public ProgrammingExerciseParticipation retrieveParticipationForRepository(String repositoryTypeOrUserName, String repositoryURI) {
if (repositoryTypeOrUserName.equals(RepositoryType.SOLUTION.toString()) || repositoryTypeOrUserName.equals(RepositoryType.TESTS.toString())) {
return solutionParticipationRepository.findByRepositoryUriElseThrow(repositoryURI);
}
if (repositoryTypeOrUserName.equals(RepositoryType.TEMPLATE.toString())) {
return templateParticipationRepository.findByRepositoryUriElseThrow(repositoryURI);
}
if (repositoryTypeOrUserName.equals(RepositoryType.AUXILIARY.toString())) {
throw new EntityNotFoundException("Auxiliary repositories do not have participations.");
}
return studentParticipationRepository.findByRepositoryUriElseThrow(repositoryURI);
}

/**
* Get the commits information for the given participation.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.UploadPack;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

Expand All @@ -31,6 +32,13 @@ public ArtemisGitServletService(LocalVCServletService localVCServletService) {

/**
* Initialize the ArtemisGitServlet by setting the repository resolver and adding filters for fetch and push requests.
* Sets the pre/post receive/upload hooks.
* <p>
* For general information on the different hooks and git packs see the git documentation:
* <p>
* <a href="https://git-scm.com/docs/git-receive-pack">https://git-scm.com/docs/git-receive-pack</a>
* <p>
* <a href="https://git-scm.com/docs/git-upload-pack">https://git-scm.com/docs/git-upload-pack</a>
*/
@PostConstruct
@Override
Expand All @@ -55,5 +63,13 @@ public void init() {
receivePack.setPostReceiveHook(new LocalVCPostPushHook(localVCServletService));
return receivePack;
});

this.setUploadPackFactory((request, repository) -> {
UploadPack uploadPack = new UploadPack(repository);

// Add the custom pre-upload hook, to distinguish between clone and pull operations
uploadPack.setPreUploadHook(new LocalVCFetchPreUploadHook(localVCServletService, request));
return uploadPack;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.filter.OncePerRequestFilter;

import de.tum.cit.aet.artemis.core.exception.localvc.LocalVCAuthException;
Expand Down Expand Up @@ -44,6 +45,11 @@ public void doFilterInternal(HttpServletRequest servletRequest, HttpServletRespo
servletResponse.setStatus(localVCServletService.getHttpStatusForException(e, servletRequest.getRequestURI()));
return;
}
catch (AuthenticationException e) {
// intercept failed authentication to log it in the VCS access log
localVCServletService.createVCSAccessLogForFailedAuthenticationAttempt(servletRequest);
throw e;
}

filterChain.doFilter(servletRequest, servletResponse);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package de.tum.cit.aet.artemis.programming.service.localvc;

import java.util.Collection;

import jakarta.servlet.http.HttpServletRequest;

import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.transport.PreUploadHook;
import org.eclipse.jgit.transport.UploadPack;

public class LocalVCFetchPreUploadHook implements PreUploadHook {

private final LocalVCServletService localVCServletService;

private final HttpServletRequest request;

public LocalVCFetchPreUploadHook(LocalVCServletService localVCServletService, HttpServletRequest request) {
this.localVCServletService = localVCServletService;
this.request = request;
}

@Override
public void onBeginNegotiateRound(UploadPack uploadPack, Collection<? extends ObjectId> collection, int clientOffered) {
localVCServletService.updateVCSAccessLogForCloneAndPullHTTPS(request, clientOffered);
}

@Override
public void onEndNegotiateRound(UploadPack uploadPack, Collection<? extends ObjectId> collection, int i, int i1, boolean b) {
}

@Override
public void onSendPack(UploadPack uploadPack, Collection<? extends ObjectId> collection, Collection<? extends ObjectId> collection1) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package de.tum.cit.aet.artemis.programming.service.localvc;

import java.nio.file.Path;
import java.util.Collection;

import org.apache.sshd.server.session.ServerSession;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.transport.PreUploadHook;
import org.eclipse.jgit.transport.UploadPack;

public class LocalVCFetchPreUploadHookSSH implements PreUploadHook {

private final LocalVCServletService localVCServletService;

private final ServerSession serverSession;

private final Path rootDir;

public LocalVCFetchPreUploadHookSSH(LocalVCServletService localVCServletService, ServerSession serverSession, Path rootDir) {
this.localVCServletService = localVCServletService;
this.serverSession = serverSession;
this.rootDir = rootDir;
}

@Override
public void onBeginNegotiateRound(UploadPack uploadPack, Collection<? extends ObjectId> collection, int clientOffered) {
localVCServletService.updateVCSAccessLogForCloneAndPullSSH(serverSession, rootDir, clientOffered);
}

@Override
public void onEndNegotiateRound(UploadPack uploadPack, Collection<? extends ObjectId> collection, int i, int i1, boolean b) {
}

@Override
public void onSendPack(UploadPack uploadPack, Collection<? extends ObjectId> collection, Collection<? extends ObjectId> collection1) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public void doFilterInternal(HttpServletRequest servletRequest, HttpServletRespo
servletResponse.setStatus(localVCServletService.getHttpStatusForException(e, servletRequest.getRequestURI()));
return;
}
this.localVCServletService.updateVCSAccessLogForPushHTTPS(servletRequest);

filterChain.doFilter(servletRequest, servletResponse);

Expand Down
Loading

0 comments on commit 74f70a8

Please sign in to comment.