Commit b6df93a5 authored by Vincent Wong's avatar Vincent Wong

Record and show last used date of SSH Keys

Addresses: Issue #13810

1. Adds a last_used_at attribute to the Key table/model
2. Update a key's last_used_at whenever it gets used
3. Display how long ago an ssh key was last used
parent f264ec6e
...@@ -49,6 +49,10 @@ class Key < ActiveRecord::Base ...@@ -49,6 +49,10 @@ class Key < ActiveRecord::Base
"key-#{id}" "key-#{id}"
end end
def update_last_used_at
UseKeyWorker.perform_async(self.id)
end
def add_to_shell def add_to_shell
GitlabShellWorker.perform_async( GitlabShellWorker.perform_async(
:add_key, :add_key,
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
= key.title = key.title
.description .description
= key.fingerprint = key.fingerprint
.last-used-at
last used:
= key.last_used_at ? time_ago_with_tooltip(key.last_used_at) : 'n/a'
.pull-right .pull-right
%span.key-created-at %span.key-created-at
created #{time_ago_with_tooltip(key.created_at)} created #{time_ago_with_tooltip(key.created_at)}
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
%li %li
%span.light Created on: %span.light Created on:
%strong= @key.created_at.to_s(:medium) %strong= @key.created_at.to_s(:medium)
%li
%span.light Last used on:
%strong= @key.last_used_at.try(:to_s, :medium) || 'N/A'
.col-md-8 .col-md-8
%p %p
......
class UseKeyWorker
include Sidekiq::Worker
include DedicatedSidekiqQueue
def perform(key_id)
key = Key.find(key_id)
key.touch(:last_used_at)
rescue ActiveRecord::RecordNotFound
Rails.logger.error("UseKeyWorker: couldn't find key with ID=#{key_id}, skipping job")
false
end
end
---
title: Record and show last used date of SSH Keys
merge_request: 8113
author: Vincent Wong
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
- [email_receiver, 2] - [email_receiver, 2]
- [emails_on_push, 2] - [emails_on_push, 2]
- [mailers, 2] - [mailers, 2]
- [use_key, 1]
- [repository_fork, 1] - [repository_fork, 1]
- [repository_import, 1] - [repository_import, 1]
- [project_service, 1] - [project_service, 1]
......
class AddLastUsedAtToKey < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :keys, :last_used_at, :datetime
end
end
...@@ -528,6 +528,7 @@ ActiveRecord::Schema.define(version: 20161226122833) do ...@@ -528,6 +528,7 @@ ActiveRecord::Schema.define(version: 20161226122833) do
t.string "fingerprint" t.string "fingerprint"
t.boolean "public", default: false, null: false t.boolean "public", default: false, null: false
t.boolean "can_push", default: false, null: false t.boolean "can_push", default: false, null: false
t.datetime "last_used_at"
end end
add_index "keys", ["fingerprint"], name: "index_keys_on_fingerprint", unique: true, using: :btree add_index "keys", ["fingerprint"], name: "index_keys_on_fingerprint", unique: true, using: :btree
......
...@@ -28,6 +28,8 @@ module API ...@@ -28,6 +28,8 @@ module API
protocol = params[:protocol] protocol = params[:protocol]
actor.update_last_used_at if actor.is_a?(Key)
access = access =
if wiki? if wiki?
Gitlab::GitAccessWiki.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities) Gitlab::GitAccessWiki.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities)
...@@ -61,6 +63,8 @@ module API ...@@ -61,6 +63,8 @@ module API
status 200 status 200
key = Key.find(params[:key_id]) key = Key.find(params[:key_id])
key.update_last_used_at
token_handler = Gitlab::LfsToken.new(key) token_handler = Gitlab::LfsToken.new(key)
{ {
...@@ -103,7 +107,9 @@ module API ...@@ -103,7 +107,9 @@ module API
key = Key.find_by(id: params[:key_id]) key = Key.find_by(id: params[:key_id])
unless key if key
key.update_last_used_at
else
return { 'success' => false, 'message' => 'Could not find the given key' } return { 'success' => false, 'message' => 'Could not find the given key' }
end end
......
...@@ -248,6 +248,7 @@ DeployKey: ...@@ -248,6 +248,7 @@ DeployKey:
- fingerprint - fingerprint
- public - public
- can_push - can_push
- last_used_at
Service: Service:
- id - id
- type - type
......
...@@ -28,6 +28,15 @@ describe Key, models: true do ...@@ -28,6 +28,15 @@ describe Key, models: true do
expect(build(:key, user: user).publishable_key).to include("#{user.name} (#{Gitlab.config.gitlab.host})") expect(build(:key, user: user).publishable_key).to include("#{user.name} (#{Gitlab.config.gitlab.host})")
end end
end end
describe "#update_last_used_at" do
it "enqueues a UseKeyWorker job" do
key = create(:key)
expect(UseKeyWorker).to receive(:perform_async).with(key.id)
key.update_last_used_at
end
end
end end
context "validation of uniqueness (based on fingerprint uniqueness)" do context "validation of uniqueness (based on fingerprint uniqueness)" do
......
require 'spec_helper'
describe UseKeyWorker do
describe "#perform" do
it "updates the key's last_used_at attribute to the current time when it exists" do
worker = described_class.new
key = create(:key)
current_time = Time.zone.now
Timecop.freeze(current_time) do
expect { worker.perform(key.id) }
.to change { key.reload.last_used_at }.from(nil).to be_like_time(current_time)
end
end
it "returns false and skips the job when the key doesn't exist" do
worker = described_class.new
key = create(:key)
expect(worker.perform(key.id + 1)).to eq false
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment